CollectUICollectUI

Default Monorepo

Install and use the HeroUI Pro component library in a default monorepo project (Web only)

This article was written by a human (md) and optimized by AI (mdx).

Create a default monorepo with Better T Stack (go to Builder).

Tech stack:

Tech stack selection

The Bun above is the runtime, while the bun below is the package manager. (bun can serve as both a runtime and a package manager.)

Also, choosing a different stack is fine — the installation options and specific paths may differ. The following uses this stack as an example.

One-Step Setup

Skip the manual installation process and use a template based on the current example.

Clone the template

npx -y degit rhywonfeong/hp-default-monorepo-template my-better-t-app
cd my-better-t-app

degit clones the repository but discards the remote git history.

Make sure the p cli is installed, then run the following from any path:

p clone --degit rhywonfeong/hp-default-monorepo-template my-better-t-app

It clones the remote repository in degit mode, places it in a unified project directory (for easier management), and opens it with your IDE (cursor by default).

Install dependencies

bun install

Run hpsetup

Start the preview

bun dev

Manual Installation

Create with the CLI

bun create better-t-stack@latest my-better-t-app --yes

The default configuration command is the most concise. With slight modifications, many flag options appear.

Verify it runs (optional)

Run the dev preview to check if everything works.

bun dev

Verify it runs

If everything looks good, stop the server and continue.

Stage and commit (optional)

It's recommended to make a commit so you can easily review changes later, and quickly revert if something goes wrong.

git status

There is one initial commit (auto-created by better-t-stack) and two changes (one auto-generated, and one local db that is currently empty).

Ignore them all:

.gitignore
# Custom Ignore
local.db
*.gen.ts

Stage and commit:

git add -A && git commit -m "wip: checkpoint before next changes"
git add -A; git commit -m "wip: checkpoint before next changes"

Install HeroUI Pro

Run hpsetup

Run hpsetup from the root directory:

hpsetup supports monorepos and can be run directly from the root directory — it can add and install to sub-projects without needing to cd into them, which the official CLI does not support.

Select Install HeroUI React Pro, then install all pre-selected peer dependencies.

You can also install them partially, since not every imported pro component requires all of these peer dependencies. However, the problem is you don't know which peer dependencies an imported pro component needs, and some of them are required.

hpsetup interactive installation

The version here was restored from the local cache, consistent with the official CLI behavior. The tarball for each version is fixed.

It can also be automated, which is suitable for CI scenarios (it auto-detects, so you don't need to manually add the --auto flag).

hpsetup automated installation

Import Pro styles

packages/ui/src/styles/globals.css
@import "tailwindcss";
@import "@heroui/styles";
@import "@heroui-pro/react/css";
Import Pro styles

Import a Pro component

apps/web/src/components/area-chart-demo.tsx
"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 (@heroui-pro/react). Importing from the main entry may trigger dependency resolution errors or build failures. See Using Subpath Imports for details.

Preview on the home page

apps/web/src/routes/index.tsx
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>
  );
}

Start the development server:

bun dev

Component rendering

Remove shadcn Styles

It renders without errors, but the styles aren't quite right.

Same old problem — better-t-stack creates a monorepo that uses shadcn/ui by default. So we're essentially introducing heroui (v3) into a shadcn/ui project. Two completely different UI component libraries/frameworks cause some style issues (some heroui styles get overridden by shadcn).

As such, we can completely remove shadcn and use only heroui.

Mixing them is not recommended. Even if the current component's styles can be fixed (by removing the shadcn styles that override heroui), other components you introduce later may still have issues.

First, remove the other styles from globals.css and see if everything works.

packages/ui/src/styles/globals.css
@import "tailwindcss";
@import "@heroui/styles";
@import "@heroui-pro/react/css";
@import "tw-animate-css";
@import "shadcn/tailwind.css";
@source "../../../apps/**/*.{ts,tsx}";
@source "../**/*.{ts,tsx}";
@custom-variant dark (&:is(.dark *));
:root { ... }
.dark { ... }
@theme inline { ... }
@layer base { ... }

Renders correctly

Renders correctly 😎

Of course, shadcn isn't completely removed yet. For the full cleanup details, see shadcn Cleanup Summary.

If you want to skip the cleanup process, you can also use the ready-made template, published by p cli based on the current example.

Template preview

For a quick start, see One-Step Setup.

How is this guide?

Last updated on

On this page