Web + Native Monorepo
Install and use HeroUI Pro component library in a Web + Native monorepo project
This article is manually written (md) and AI-optimized (mdx).
In a Web + Native full-stack monorepo, hpsetup can be run from the root directory. It will automatically detect all Pro packages in the workspaces and install them.
Create a Project
Initialize a monorepo project with Turborepo using create better-t-stack:
pnpm create better-t-stack@latest my-better-t-app \
--frontend tanstack-router native-uniwind \
--backend none \
--runtime none \
--api none \
--auth none \
--payments none \
--database none \
--orm none \
--db-setup none \
--package-manager pnpm \
--git \
--web-deploy none \
--server-deploy none \
--install \
--addons turborepo \
--examples noneRun hpsetup
Navigate into the project directory and run hpsetup:
Configure Styles
After installing the Pro dependencies, you need to import the styles in each project's global CSS.
Web Project
@import "tailwindcss";
@import "@heroui/styles";
@import "@heroui-pro/react/css";Native Project
@import 'tailwindcss';
@import 'uniwind';
@import 'heroui-native/styles';
@import 'heroui-native-pro/styles';
@source './node_modules/heroui-native/lib';
@source './node_modules/heroui-native-pro/lib';Add Example Components
Create Pro components in each project's components/ directory.
Web: AreaChart
"use client";
import {Card} from "@heroui/react";
import { ChartTooltip } from "@heroui-pro/react/chart-tooltip";
import {AreaChart} from "@heroui-pro/react/area-chart";
const revenueData = [
{month: "Jan", revenue: 4200},
{month: "Feb", revenue: 5800},
{month: "Mar", revenue: 4900},
{month: "Apr", revenue: 7200},
{month: "May", revenue: 6100},
{month: "Jun", revenue: 8400},
{month: "Jul", revenue: 7800},
{month: "Aug", revenue: 9200},
{month: "Sep", revenue: 8600},
{month: "Oct", revenue: 10200},
{month: "Nov", revenue: 9800},
{month: "Dec", revenue: 11500},
];
export default function AreaChartDemo() {
return (
<Card className="w-full max-w-[520px] rounded-2xl">
<Card.Header>
<Card.Title className="text-base">Monthly Revenue</Card.Title>
</Card.Header>
<Card.Content>
<AreaChart data={revenueData} height={200}>
<defs>
<linearGradient id="revenue-fill" x1="0" x2="0" y1="0" y2="1">
<stop offset="0%" stopColor="var(--chart-3)" stopOpacity={0.2} />
<stop offset="100%" stopColor="var(--chart-3)" stopOpacity={0.02} />
</linearGradient>
</defs>
<AreaChart.Grid vertical={false} />
<AreaChart.XAxis dataKey="month" tickMargin={8} />
<AreaChart.YAxis tickFormatter={(v: number) => `$${(v / 1000).toFixed(0)}k`} width={40} />
<AreaChart.Area
dataKey="revenue"
dot={false}
fill="url(#revenue-fill)"
name="Revenue"
stroke="var(--chart-3)"
strokeWidth={2}
type="monotone"
/>
<AreaChart.Tooltip
content={({active, label, payload}) => {
if (!active || !payload?.length) return null;
return (
<ChartTooltip>
<ChartTooltip.Header>{label}</ChartTooltip.Header>
{payload.map((entry) => (
<ChartTooltip.Item key={String(entry.dataKey)}>
<ChartTooltip.Indicator color={entry.color ?? entry.stroke} />
<ChartTooltip.Label>{entry.name}</ChartTooltip.Label>
<ChartTooltip.Value>
${Number(entry.value).toLocaleString()}
</ChartTooltip.Value>
</ChartTooltip.Item>
))}
</ChartTooltip>
);
}}
/>
</AreaChart>
</Card.Content>
</Card>
);
}Note that the import path above uses a subpath (@heroui-pro/react/area-chart) rather than the main entry point (@heroui-pro/react). Importing from the main entry point may trigger dependency resolution errors or bundling issues. See Using Subpath Imports.
Native: Stepper
import { Stepper } from 'heroui-native-pro';
import { View } from 'react-native';
export default function StepperDemo() {
return (
<View className="flex-1 justify-center bg-background p-4">
<Stepper>
<Stepper.Step>
<Stepper.Rail />
<Stepper.Content>
<Stepper.Title>Account</Stepper.Title>
<Stepper.Description>Create your account</Stepper.Description>
</Stepper.Content>
</Stepper.Step>
<Stepper.Step>
<Stepper.Rail />
<Stepper.Content>
<Stepper.Title>Profile</Stepper.Title>
<Stepper.Description>Set up your profile</Stepper.Description>
</Stepper.Content>
</Stepper.Step>
</Stepper>
</View>
);
}Import in Pages
Web
import { createFileRoute } from "@tanstack/react-router";
import AreaChartDemo from "@/components/area-chart-demo";
export const Route = createFileRoute("/")({
component: HomeComponent,
});
function HomeComponent() {
return (
<div className="container mx-auto max-w-3xl px-4 py-2">
<div className="grid gap-6">
<AreaChartDemo />
</div>
</div>
);
}Native
import { Text, View } from "react-native";
import { Container } from "@/components/container";
import StepperDemo from "@/components/stepper-demo";
export default function Home() {
return (
<Container className="px-4 pb-4">
<View className="py-6 mb-5">
<Text className="text-3xl font-semibold text-foreground tracking-tight">
Better T Stack
</Text>
<Text className="text-muted text-sm mt-1">Full-stack TypeScript starter</Text>
</View>
<StepperDemo />
</Container>
);
}Preview
Run pnpm run dev to start the project.
Common Issues
Web: Multiple React Instances Error
This is a multiple React instances issue caused by Vite's pre-bundling. When @heroui-pro/react internally calls React.useMemo, React is null.
Fix: Add dedupe to your Vite configuration:
export default defineConfig({
resolve: {
tsconfigPaths: true,
dedupe: ["react", "react-dom", "react/jsx-runtime"],
},
// ...
});After the fix, it renders correctly:
Web: Component Style Issues
This is related to theme variable conflicts with shadcn. Removing the shadcn theme configuration from global.css resolves the issue:
You can also have AI remove the styles in shadcn that conflict with HeroUI to mix them, but this may affect the rendering of shadcn components. It is recommended to avoid mixing them whenever possible.
Native: Skia Compatibility
If you encounter compatibility warnings related to @shopify/react-native-skia, you need to install a version compatible with your current Expo SDK:
npx -y expo install @shopify/react-native-skiaAfter the fix, the preview works correctly:

How is this guide?
Last updated on