Loading...
Loading...
shadcn/ui expert guidance — CLI, component installation, composition patterns, custom registries, theming, Tailwind CSS integration, and high-quality interface design. Use when initializing shadcn, adding components, composing product UI, building custom registries, configuring themes, or troubleshooting component issues.
npx skill4agent add vercel-labs/vercel-plugin shadcnshadcn init-d# Non-interactive init with defaults — USE THIS
npx shadcn@latest init -d
# Non-interactive with a preset (recommended for consistent design systems)
npx shadcn@latest init --preset <code> -f
# Non-interactive with explicit base library choice
npx shadcn@latest init -d --base radix
npx shadcn@latest init -d --base base-ui
# Scaffold a full project template (CLI v4)AI Elements compatibility: Always use(the default) when the project uses or may use AI Elements. AI Elements components rely on Radix APIs and have type errors with Base UI.--base radix
npx shadcn@latest init --template next -d
npx shadcn@latest init --template vite -d-d, --defaults-y, --yes-d-f, --force-t, --templatenextvitereact-routerastrolaraveltanstack-start--preset--baseradixbase-ui--monorepoWARNING:/-yalone does NOT make init fully non-interactive — it still prompts for component library selection. Always use--yesto skip ALL prompts.-d
Deprecated in CLI v4:,--style,--base-color,--src-dir, and--no-base-styleflags are removed and will error. The--css-variablesandregistry:buildregistry types are also deprecated. Useregistry:mcpandregistry:baseinstead.registry:font
components.jsoncn()# Add specific components
npx shadcn@latest add button dialog card
# Add all available components
npx shadcn@latest add --all
# Add from a custom registry
npx shadcn@latest add @v0/dashboard
npx shadcn@latest add @acme/custom-button
# Add from AI Elements registry
npx shadcn@latest add https://elements.ai-sdk.dev/api/registry/all.json-o, --overwrite-p, --path-a, --all--dry-run--diff--viewnpx shadcn@latest search button
npx shadcn@latest list @v0npx shadcn@latest build
npx shadcn@latest build ./registry.json -o ./public/r# View a registry item's source before installing
npx shadcn@latest view button
# Show project diagnostics — config, installed components, dependencies
npx shadcn@latest info
# Get docs, code, and examples for any component (agent-friendly output)
npx shadcn@latest docs button
npx shadcn@latest docs dialoggives coding agents the context to use primitives correctly — returns code examples, API reference, and usage patterns inline.shadcn docs
npx shadcn@latest migrate rtl # RTL support migration
npx shadcn@latest migrate radix # Migrate to unified radix-ui package
npx shadcn@latest migrate icons # Icon library changes
# Migrate components outside the default ui directory
npx shadcn@latest migrate radix src/components/custompnpm dlx skills add shadcn/uinew-yorkradix-ui@radix-ui/react-*// OLD — individual packages
import * as DialogPrimitive from "@radix-ui/react-dialog"
// NEW — unified package
import { Dialog as DialogPrimitive } from "radix-ui"npx shadcn@latest migrate radix@radix-ui/react-*package.jsonnpx shadcn@latest init --base base-uicomponents.json{
"$schema": "https://ui.shadcn.com/schema.json",
"style": "new-york",
"rsc": true,
"tsx": true,
"tailwind": {
"config": "tailwind.config.ts",
"css": "src/app/globals.css",
"baseColor": "zinc", // Options: gray, neutral, slate, stone, zinc, mauve, olive, mist, taupe
"cssVariables": true
},
"aliases": {
"components": "@/components",
"utils": "@/lib/utils",
"ui": "@/components/ui",
"lib": "@/lib",
"hooks": "@/hooks"
},
"registries": {
"v0": {
"url": "https://v0.dev/chat/api/registry"
},
"ai-elements": {
"url": "https://elements.ai-sdk.dev/api/registry"
}
}
}{
"registries": {
"acme": {
"url": "https://acme.com/registry/{name}.json"
},
"private": {
"url": "https://internal.company.com/registry/{name}.json",
"headers": {
"Authorization": "Bearer ${REGISTRY_TOKEN}"
}
}
}
}npx shadcn@latest add @acme/header @private/auth-formglobals.css@theme inline {
--color-background: oklch(0.145 0 0);
--color-foreground: oklch(0.985 0 0);
--color-card: oklch(0.205 0 0);
--color-card-foreground: oklch(0.985 0 0);
--color-primary: oklch(0.488 0.243 264.376);
--color-primary-foreground: oklch(0.985 0 0);
--color-secondary: oklch(0.269 0 0);
--color-secondary-foreground: oklch(0.985 0 0);
--color-muted: oklch(0.269 0 0);
--color-muted-foreground: oklch(0.708 0 0);
--color-accent: oklch(0.269 0 0);
--color-accent-foreground: oklch(0.985 0 0);
--color-destructive: oklch(0.396 0.141 25.723);
--color-border: oklch(0.269 0 0);
--color-input: oklch(0.269 0 0);
--color-ring: oklch(0.488 0.243 264.376);
--radius: 0.625rem;
/* CLI v4: radius tokens use multiplicative calc instead of additive */
--radius-xs: calc(var(--radius) * 0.5);
--radius-sm: calc(var(--radius) * 0.75);
--radius-md: calc(var(--radius) * 0.875);
--radius-lg: var(--radius);
--radius-xl: calc(var(--radius) * 1.5);
}dark<html>// app/layout.tsx
<html lang="en" className="dark">import { ThemeProvider } from 'next-themes'
<ThemeProvider attribute="class" defaultTheme="dark">
{children}
</ThemeProvider>@theme inline {
/* shadcn defaults above... */
/* Custom app colors */
--color-priority-urgent: oklch(0.637 0.237 15.163);
--color-priority-high: oklch(0.705 0.213 47.604);
--color-status-done: oklch(0.723 0.219 149.579);
}<span className="text-[var(--color-priority-urgent)]">Urgent</span>
// Or with Tailwind v4 theme():
<span className="text-priority-urgent">Urgent</span>| Component | Use Case |
|---|---|
| Actions, form submission |
| Content containers |
| Modals, confirmation prompts |
| Form fields |
| Dropdowns |
| Data display |
| View switching |
| Command palette (Cmd+K) |
| Context menus |
| Floating content |
| Hover hints |
| Status indicators |
| User profile images |
| Scrollable containers |
| Visual dividers |
| Form labels |
| Slide-out panels |
| Loading placeholders |
new-york--color-primarybg-backgroundbg-cardtext-foregroundtext-muted-foregroundborder-borderring-ring--radius: 0.625remgap-6p-6text-smgap-4p-4text-smh-4 w-4h-5 w-5| Use case | Reach for this first | Why |
|---|---|---|
| Settings page | | Clear information grouping with predictable save flows |
| Data dashboard | | Covers summary, status, dense data, and row actions without custom shells |
| CRUD table | | Supports browse, act, edit, and destructive confirmation in a standard pattern |
| Auth screen | | Keeps entry flows focused and gives errors a proper treatment |
| Global search | | Fast keyboard-first discovery with an established interaction model |
| Mobile nav | | Provides a compact navigation shell that adapts cleanly to small screens |
| Detail page | header + | Balances hierarchy, metadata, and supporting content without over-nesting |
| Filters | | Works for persistent desktop filters and collapsible mobile controls |
| Empty/loading/error states | | Gives non-happy paths a designed surface instead of placeholder text |
TabsCardSeparatorCardTableBadgeCardCardAlertDialogCommandPopoverSheetCardSeparatorAlertAlertDialogDialogbuttoninputselectdivdiv rounded-xl border p-6TabsTableSheetDialogDialogAlertDialog| Type | Purpose |
|---|---|
| Individual UI components |
| Full design system payload — components, deps, CSS vars, fonts, config |
| Font configuration as a first-class registry item |
[
{
"name": "my-component",
"type": "registry:ui",
"title": "My Component",
"description": "A custom component",
"files": [
{
"path": "components/my-component.tsx",
"type": "registry:ui"
}
],
"dependencies": ["lucide-react"]
}
]npx shadcn@latest build
# Outputs to public/r/my-component.jsonnpx shadcn@latest add https://your-domain.com/r/my-component.jsonshadcn initshadcn initglobals.css--font-sans: var(--font-sans)@theme inlinevar(--font-geist-sans)@theme inline/* In @theme inline — CORRECT (literal names) */
--font-sans: "Geist", "Geist Fallback", ui-sans-serif, system-ui, sans-serif;
--font-mono: "Geist Mono", "Geist Mono Fallback", ui-monospace, monospace;
/* WRONG — circular, resolves to nothing */
--font-sans: var(--font-sans);
/* ALSO WRONG — @theme inline can't resolve runtime CSS variables */
--font-sans: var(--font-geist-sans);shadcn init@theme inline<body><html>layout.tsx// layout.tsx — font variables on <html>, not <body>
<html lang="en" className={`${geistSans.variable} ${geistMono.variable}`}>
<body className="antialiased">sizesize// WRONG — no size variant exists
<Avatar size="lg" /> // ❌ TypeScript error / silently ignored
// CORRECT — use Tailwind
<Avatar className="h-12 w-12">
<AvatarImage src={user.image} />
<AvatarFallback>JD</AvatarFallback>
</Avatar>
// Small avatar
<Avatar className="h-6 w-6"> ... </Avatar>cvacn()import { clsx, type ClassValue } from 'clsx'
import { twMerge } from 'tailwind-merge'
export function cn(...inputs: ClassValue[]) {
return twMerge(clsx(inputs))
}// components/ui/button.tsx — add your custom variant
const buttonVariants = cva('...', {
variants: {
variant: {
default: '...',
destructive: '...',
// Add custom variants
success: 'bg-green-600 text-white hover:bg-green-700',
premium: 'bg-gradient-to-r from-purple-500 to-pink-500 text-white',
},
},
})TooltipProvider// app/layout.tsx
import { TooltipProvider } from '@/components/ui/tooltip'
export default function RootLayout({ children }) {
return (
<html lang="en" className="dark">
<body>
<TooltipProvider>{children}</TooltipProvider>
</body>
</html>
)
}# Apply a preset during init
npx shadcn@latest init --preset <code>
# Switch presets in an existing project (reconfigures everything including components)
npx shadcn@latest init --preset <code>shadcn/createnpx shadcn@latest migrate rtlml-4left-2ms-4start-2