Docs
Getting started
Bollard UI is not a package. Each component is a source file the shadcn CLI copies into your project, so you need a shadcn setup once and then one command per component.
Prerequisites
- React 19 or later. Components take
refas a plain prop, so React 18 is not supported. - Tailwind CSS v4 with the shadcn theme variables. Tailwind v3 is not targeted.
- A shadcn/ui setup: a
components.json, the theme tokens and thecn()helper in@/lib/utils. You don't need any of shadcn's own components. - TypeScript is recommended; every component is written in strict TypeScript.
If the project doesn't have a shadcn setup yet, run this once:
Add with the CLI
The CLI reads your components.json, then:
- writes the component to your
uifolder, for examplecomponents/ui/amount-input.tsx(a few components also bring a helper.tsfile that lands next to it); - installs the npm packages the component lists, such as lucide-react or motion;
- adds any other Bollard UI component it builds on.
Every component page shows its exact command, its dependencies and the files it adds. The whole registry is at /r/registry.json.
components/
ui/
amount-input.tsx ← written by the CLI, yours to edit
lib/
utils.ts ← cn(), from shadcn initAdd by hand
- Install the npm packages listed under Dependencies on the component's page.
- Open the Manual tab on the component's page, copy each file into
components/ui, keeping the file names. - Fix the imports if your aliases differ:
@/lib/utilsforcn(), and@/components/ui/…for any other Bollard UI component it imports.
Import and use
Import from where the file landed. Snippets on this site always use @/components/ui/<name>, which is what the CLI writes with the default aliases.
import { AmountInput } from "@/components/ui/amount-input"
export function RentField() {
return <AmountInput label="Monthly rent" locale="en-IN" currency="INR" typical={24000} />
}Value-holding components work controlled (value + onValueChange) or uncontrolled (defaultValue). Most user-facing strings are props with English defaults; the Props table on each page lists them.
Custom aliases
If your components.json points aliases.ui or aliases.utils somewhere else (say ~/ui), the CLI rewrites the imports in the copied files to match. When you copy by hand, change those imports yourself. Check that the alias also exists in tsconfig.json (and in your bundler config for Vite).
Updating a component
Copied code doesn't update itself. Fixes and rule changes are listed in the changelog. To pick one up, either re-run the add command with --overwrite, which replaces your file (commit first so you can see and keep your own edits):
or compare your copy with the published source in /r/<name>.json and merge by hand:
# Fetch the current source and compare it with your copy
curl -s https://bollard-ui.vercel.app/r/amount-input.json | jq -r '.files[0].content' > /tmp/amount-input.tsx
git diff --no-index components/ui/amount-input.tsx /tmp/amount-input.tsxNext.js
- App Router works as is. Components that use hooks start with
"use client", so you can render them from Server Components. - They never touch
window,documentorlocalStorageduring render, so server rendering is safe. create-next-appalready sets the@/*alias; runshadcn initand add components.
Vite
Set up Tailwind v4 with @tailwindcss/vite and the @ alias before running shadcn init, as the shadcn Vite guide describes. The "use client" lines are harmless outside Next.js.
// vite.config.ts
import path from "node:path"
import tailwindcss from "@tailwindcss/vite"
import react from "@vitejs/plugin-react"
import { defineConfig } from "vite"
export default defineConfig({
plugins: [react(), tailwindcss()],
resolve: { alias: { "@": path.resolve(__dirname, "./src") } },
})Guard rails, not enforcement
Not sure where to begin? Start here has the essentials, or browse every component.