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
Install the peer dependencies
npm i clsx tailwind-merge class-variance-authority @phosphor-icons/reactThese 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.
Add the tokens and the cn() helper
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.
@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.
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).
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>
)
}Add a component and use it
npx @agents-npm-packages/vibeui add button dialog --dir ./src/components/uiComponents 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.
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.
{
"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.
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.
- Copy the file into
src/components/ui/. - Copy any sibling it lists (for example
button.tsx). - Install any extra peers shown on the page.
Troubleshooting
| Symptom | Likely cause and fix |
|---|---|
| Components render unstyled or with default Tailwind radii | The tokens are not imported, or are imported before @import "tailwindcss". Import them after. |
| Animations do nothing in my app | Keyframes 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 toggle | The @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 useState | The 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 Component | Import 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.