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 ref as 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 the cn() 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:

pnpm dlx shadcn@latest init

Add with the CLI

pnpm dlx shadcn@latest add https://bollard-ui.vercel.app/r/amount-input.json

The CLI reads your components.json, then:

  1. writes the component to your ui folder, for example components/ui/amount-input.tsx (a few components also bring a helper .ts file that lands next to it);
  2. installs the npm packages the component lists, such as lucide-react or motion;
  3. 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.

project
components/
  ui/
    amount-input.tsx   ← written by the CLI, yours to edit
lib/
  utils.ts             ← cn(), from shadcn init

Add by hand

  1. Install the npm packages listed under Dependencies on the component's page.
  2. Open the Manual tab on the component's page, copy each file into components/ui, keeping the file names.
  3. Fix the imports if your aliases differ: @/lib/utils for cn(), 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.

rent-field.tsx
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):

pnpm dlx shadcn@latest add https://bollard-ui.vercel.app/r/amount-input.json --overwrite

or compare your copy with the published source in /r/<name>.json and merge by hand:

terminal
# 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.tsx

Next.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, document or localStorage during render, so server rendering is safe.
  • create-next-app already sets the @/* alias; run shadcn init and 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

Bollard UI components catch honest mistakes in the browser. They don't replace server-side validation, authorization, rate limits, idempotency keys or database constraints, and anyone can bypass client code. Pages for security, payment and destructive components say what the server still has to enforce. See also Security.

Not sure where to begin? Start here has the essentials, or browse every component.