Getting started

Installation

From an empty React app to a working component in about two minutes. Pick your framework for the one step that differs.

Prerequisites

You need a React 18+ project with Tailwind CSS v4 and a @/* path alias pointing at src/*. A fresh create-next-app or Vite React-TS template satisfies the alias already; if you are adding VibeUI to an existing project, check the alias section below.

Setup

1

Install the peer dependencies

bash
npm i clsx tailwind-merge class-variance-authority @phosphor-icons/react

These are the only runtime dependencies. @phosphor-icons/react supplies the icons; files without "use client" import from @phosphor-icons/react/dist/ssr so they stay server-safe.

2

Add the tokens and the cn() helper

bash
npx @agents-npm-packages/vibeui init --dir .

This writes vibeui.tokens.css (all design tokens, keyframes and the dark variant) and src/lib/utils.ts (the cn() helper). It will not overwrite files that already exist. You can also copy templates/vibeui.css by hand.

Then import the tokens after Tailwind. Order matters: the token file declares theme values and a custom variant that Tailwind has to see.

src/app/globals.css
@import "tailwindcss";
@import "../../vibeui.tokens.css";

Next.js already includes the Tailwind PostCSS plugin when you pick Tailwind in create-next-app. If you added Tailwind manually, install tailwindcss and @tailwindcss/postcss and register the plugin in postcss.config.mjs.

3

Add fonts (optional)

The tokens reference three optional font variables. If you do nothing, the system font stack is used. The VibeUI look uses Geist for UI, Geist Mono for code and Instrument Serif for display type (all open source under the SIL Open Font License).

app/layout.tsx
import { Geist, Geist_Mono, Instrument_Serif } from "next/font/google"

const sans = Geist({ variable: "--font-geist-sans", subsets: ["latin"] })
const mono = Geist_Mono({ variable: "--font-geist-mono", subsets: ["latin"] })
const display = Instrument_Serif({
  variable: "--font-instrument",
  subsets: ["latin"],
  weight: "400",
  style: ["normal", "italic"],
})

export default function RootLayout({ children }: { children: React.ReactNode }) {
  return (
    <html lang="en" className={`${sans.variable} ${mono.variable} ${display.variable}`}>
      <body className="bg-canvas font-sans text-ink">{children}</body>
    </html>
  )
}
4

Add a component and use it

bash
npx @agents-npm-packages/vibeui add button dialog --dir ./src/components/ui

Components that import siblings bring them along. Adding footer-cta also copies button, so you never end up with a broken import. The CLI prints the list of peers it expects.

app/page.tsx
import { Button } from "@/components/ui/button"

export default function Page() {
  return <Button variant="accent">Get started</Button>
}

Path alias

Every component imports cn from @/lib/utils. If your project uses a different alias, either add the one below or find-and-replace the import after copying.

tsconfig.json
{
  "compilerOptions": {
    "baseUrl": ".",
    "paths": { "@/*": ["./src/*"] }
  }
}

Providers

Almost everything is self-contained. The one exception is toasts: wrap your app once in ToastProvider, then call useToast() anywhere beneath it.

app/layout.tsx
import { ToastProvider } from "@/components/ui/toast"

export default function RootLayout({ children }) {
  return (
    <html lang="en">
      <body>
        <ToastProvider>{children}</ToastProvider>
      </body>
    </html>
  )
}

For dark mode you will also want the inline theme script and, if you want a toggle, a tiny provider. Both are covered in Dark mode.

Installing by hand

You do not need the CLI. Every component page in the gallery shows the full source with a copy button and lists its peers and any sibling components it imports.

  1. Copy the file into src/components/ui/.
  2. Copy any sibling it lists (for example button.tsx).
  3. Install any extra peers shown on the page.

Troubleshooting

SymptomLikely cause and fix
Components render unstyled or with default Tailwind radiiThe tokens are not imported, or are imported before @import "tailwindcss". Import them after.
Animations do nothing in my appKeyframes and animate-* utilities live in the token file. Make sure the whole file was imported, not just the color variables.
dark: utilities follow the OS, not my toggleThe @custom-variant dark line is missing. It ships at the top of the token file.
Cannot find module '@/lib/utils'Add the path alias above, or run init so utils.ts exists.
Error: You're importing a component that needs useStateThe file needs "use client". Components that use state already have it; if you wrap one in a Server Component that passes functions as props, move that wrapper to a client file.
Icons break in a Server ComponentImport from @phosphor-icons/react/dist/ssr in files without "use client".

Verify it works

Render a Switch and a Slider. If the switch track is the accent color when on, and the slider has a filled track, the tokens are wired correctly.