shadcn/ui
A framework for building ui, components and design systems. Components are added as source code to the user's project via the CLI.
AI-Driven Workflow (Vibe Coding)
When working as an AI assistant, follow this "Vibe Coding" workflow. The user focuses on the "vibe" and "vision," while the AI handles the technical execution via the CLI.
- Direct Execution: When a user asks for UI (e.g., "Add a login form", "Create a dashboard"), do not just provide code. Use the
npx shadcn@latest add command directly in the terminal to install dependencies and source code.
- Context Alignment: Always check
npx shadcn@latest info --json to ensure you are using the correct framework, aliases, and icon libraries.
- Prompt-to-CLI Mapping:
- "Add a login form..." ->
npx shadcn@latest add form input button
- "Create a settings page..." ->
npx shadcn@latest add tabs card form
- "Build a dashboard..." ->
npx shadcn@latest add sidebar table chart
- "Switch to --preset [CODE]" ->
npx shadcn@latest init --preset [CODE] --force
- "Can you add a hero from @tailark?" ->
npx shadcn@latest add @tailark/hero
- Composition over Snippets: After adding primitives via CLI, compose the final UI in the target file using the project's established patterns (e.g.,
FieldGroup, SectionShell).
- Proactive Discovery: Use
npx shadcn@latest search or docs to find the best components for the user's request before asking for clarification.
IMPORTANT: Run all CLI commands using the project's package runner: npx shadcn@latest, pnpm dlx shadcn@latest, or bunx --bun shadcn@latest — based on the project's packageManager. Examples below use npx shadcn@latest but substitute the correct runner for the project.
Current Project Context
!`npx shadcn@latest info --json 2>/dev/null || echo '{"error": "No shadcn project found. Run shadcn init first."}'`
The JSON above contains the project config and installed components. Use npx shadcn@latest docs <component> to get documentation and example URLs for any component.
Principles
- Use existing components first. Use
npx shadcn@latest search to check registries before writing custom UI. Check community registries too.
- Compose, don't reinvent. Settings page = Tabs + Card + form controls. Dashboard = Sidebar + Card + Chart + Table.
- Use built-in variants before custom styles.
variant="outline", size="sm", etc.
- Use semantic colors.
bg-primary, text-muted-foreground — never raw values like bg-blue-500.
Component-First Mandate
When working in a project that already has a populated components/ui directory, treat shadcn as a component composition system, not a styling suggestion.
- Maximise reuse of installed primitives. If the UI can reasonably be expressed with existing shadcn components, do that before writing custom markup.
- Prefer richer composition over plain wrappers. A good shadcn screen should usually contain several cooperating primitives:
Card + Tabs + ScrollArea, Dialog + Form + Button, Popover + Command, etc.
- Avoid browser-native UI for app interactions when a local shadcn primitive exists.
window.prompt → Dialog + Input/Textarea
window.confirm → AlertDialog
- ad hoc tooltips/help bubbles →
Tooltip, HoverCard, or Popover
- Do not default to raw
div + border + padding for panels, menus, empty states, sidebars, or overlays. Reach for a component recipe first.
- Use multiple components when the surface benefits from structure. The goal is not fewer imports; the goal is a better-composed interface.
Current Project Inventory
For this PMTL_VN repo, the installed local shadcn/radix primitives include:
- Core structure:
card, separator, resizable, scroll-area, collapsible, accordion, tabs, sidebar, sheet, drawer
- Actions and feedback:
button, badge, alert, alert-dialog, sonner, progress, skeleton
- Inputs and forms:
form, input, textarea, select, switch, checkbox, radio-group, toggle, toggle-group, slider, input-otp, calendar
- Navigation:
breadcrumb, navigation-menu, menubar, pagination, command
- Overlays and detail affordances:
dialog, popover, hover-card, tooltip, dropdown-menu, context-menu
- Data display:
avatar, table, chart, carousel, aspect-ratio
- Local project extras:
feature-card, section-shell
Because this project uses base: radix, these components are already enough to build most interface patterns without inventing custom wrappers.
Preferred Recipes
When generating or editing UI, prefer these recipes by default:
- Page shell:
SectionShell or layout container + Breadcrumb + Card
- Reading/detail page:
Card + Badge + ScrollArea + Tabs/Collapsible + Popover/HoverCard
- Dense sidebar:
Card + ScrollArea + Collapsible + Button + Badge
- Search/filter panel:
Input + Select + ToggleGroup + Badge + Popover/Command
- Modal workflow:
Dialog + DialogHeader + Form + Button
- Dangerous action:
AlertDialog
- Inline status/info:
Alert, Badge, Tooltip
- Long lists:
ScrollArea + Card or Table
- Stepper/sectioned content:
Tabs, Accordion, or Collapsible
- Metrics/dashboard:
Card + Chart + Progress + Badge
- Media display:
AspectRatio + Carousel
Diversity Heuristic
When a user asks for "đẹp", "xịn", "đa dạng", "radix-like", or a premium UI, bias toward using more of the right primitives together, not toward custom ornament.
- Good:
CardHeader, CardContent, Badge, Separator, ScrollArea, Dialog, HoverCard, Tooltip
- Weak: one big
div with manual padding/border and a few styled buttons
Use this rule of thumb:
- If a screen has 3 or more distinct interaction zones, it should usually use at least 3 different shadcn primitives.
- If a screen has an action that opens, reveals, filters, confirms, or annotates something, it should usually use the corresponding overlay/disclosure primitive instead of custom stateful markup.
- If the layout feels visually flat, increase structure with composition (
CardHeader, CardDescription, Separator, grouped Badges, ScrollArea) before adding decorative CSS.
Critical Rules
These rules are always enforced. Each links to a file with Incorrect/Correct code pairs.
Styling & Tailwind → styling.md
className for layout, not styling. Never override component colors or typography.
- No
space-x-* or space-y-*. Use flex with gap-*. For vertical stacks, flex flex-col gap-*.
- Use
size-* when width and height are equal. size-10 not w-10 h-10.
- Use
truncate shorthand. Not overflow-hidden text-ellipsis whitespace-nowrap.
- No manual
dark: color overrides. Use semantic tokens (bg-background, text-muted-foreground).
- Use
cn() for conditional classes. Don't write manual template literal ternaries.
- No manual
z-index on overlay components. Dialog, Sheet, Popover, etc. handle their own stacking.
Forms & Inputs → forms.md
- Forms use
FieldGroup + Field. Never use raw div with space-y-* or grid gap-* for form layout.
InputGroup uses InputGroupInput/InputGroupTextarea. Never raw Input/Textarea inside InputGroup.
- Buttons inside inputs use
InputGroup + InputGroupAddon.
- Option sets (2–7 choices) use
ToggleGroup. Don't loop Button with manual active state.
FieldSet + FieldLegend for grouping related checkboxes/radios. Don't use a div with a heading.
- Field validation uses
data-invalid + aria-invalid. data-invalid on Field, aria-invalid on the control. For disabled: data-disabled on Field, disabled on the control.
- Items always inside their Group.
SelectItem → SelectGroup. DropdownMenuItem → DropdownMenuGroup. CommandItem → CommandGroup.
- Use
asChild (radix) or render (base) for custom triggers. Check base field from npx shadcn@latest info. → base-vs-radix.md
- Dialog, Sheet, and Drawer always need a Title.
DialogTitle, SheetTitle, DrawerTitle required for accessibility. Use className="sr-only" if visually hidden.
- Use full Card composition.
CardHeader/CardTitle/CardDescription/CardContent/CardFooter. Don't dump everything in CardContent.
- Button has no
isPending/isLoading. Compose with Spinner + data-icon + disabled.
TabsTrigger must be inside TabsList. Never render triggers directly in Tabs.
Avatar always needs AvatarFallback. For when the image fails to load.
Use Components, Not Custom Markup → composition.md
- Use existing components before custom markup. Check if a component exists before writing a styled
div.
- Callouts use
Alert. Don't build custom styled divs.
- Empty states use
Empty. Don't build custom empty state markup.
- Toast via
sonner. Use toast() from sonner.
- Use
Separator instead of <hr> or <div className="border-t">.
- Use
Skeleton for loading placeholders. No custom animate-pulse divs.
- Use
Badge instead of custom styled spans.
- Use
Dialog/Sheet/Drawer/AlertDialog instead of browser-native prompt/confirm flows.
- Use
ScrollArea for constrained panels and sidebars instead of raw overflowing containers when the list can grow.
- Use
CardHeader/CardDescription/CardContent to create hierarchy before adding custom wrappers inside cards.
- Icons in
Button use data-icon. data-icon="inline-start" or data-icon="inline-end" on the icon.
- No sizing classes on icons inside components. Components handle icon sizing via CSS. No
size-4 or w-4 h-4.
- Pass icons as objects, not string keys.
icon={CheckIcon}, not a string lookup.
CLI
- Never decode or fetch preset codes manually. Pass them directly to
npx shadcn@latest init --preset <code>.
Key Patterns
These are the most common patterns that differentiate correct shadcn/ui code. For edge cases, see the linked rule files above.
// Form layout: FieldGroup + Field, not div + Label.
<FieldGroup>
<Field>
<FieldLabel htmlFor="email">Email</FieldLabel>
<Input id="email" />
</Field>
</FieldGroup>
// Validation: data-invalid on Field, aria-invalid on the control.
<Field data-invalid>
<FieldLabel>Email</FieldLabel>
<Input aria-invalid />
<FieldDescription>Invalid email.</FieldDescription>
</Field>
// Icons in buttons: data-icon, no sizing classes.
<Button>
<SearchIcon data-icon="inline-start" />
Search
</Button>
// Spacing: gap-*, not space-y-*.
<div className="flex flex-col gap-4"> // correct
<div className="space-y-4"> // wrong
// Equal dimensions: size-*, not w-* h-*.
<Avatar className="size-10"> // correct
<Avatar className="w-10 h-10"> // wrong
// Status colors: Badge variants or semantic tokens, not raw colors.
<Badge variant="secondary">+20.1%</Badge> // correct
<span className="text-emerald-600">+20.1%</span> // wrong
Component Selection
| Need |
Use |
| Button/action |
Button with appropriate variant |
| Form inputs |
Input, Select, Combobox, Switch, Checkbox, RadioGroup, Textarea, InputOTP, Slider |
| Toggle between 2–5 options |
ToggleGroup + ToggleGroupItem |
| Data display |
Table, Card, Badge, Avatar |
| Navigation |
Sidebar, NavigationMenu, Breadcrumb, Tabs, Pagination |
| Overlays |
Dialog (modal), Sheet (side panel), Drawer (bottom sheet), AlertDialog (confirmation) |
| Feedback |
sonner (toast), Alert, Progress, Skeleton, Spinner |
| Command palette |
Command inside Dialog |
| Charts |
Chart (wraps Recharts) |
| Layout |
Card, Separator, Resizable, ScrollArea, Accordion, Collapsible |
| Empty states |
Empty |
| Menus |
DropdownMenu, ContextMenu, Menubar |
| Tooltips/info |
Tooltip, HoverCard, Popover |
Key Fields
The injected project context contains these key fields:
aliases → use the actual alias prefix for imports (e.g. @/, ~/), never hardcode.
isRSC → when true, components using useState, useEffect, event handlers, or browser APIs need "use client" at the top of the file. Always reference this field when advising on the directive.
tailwindVersion → "v4" uses @theme inline blocks; "v3" uses tailwind.config.js.
tailwindCssFile → the global CSS file where custom CSS variables are defined. Always edit this file, never create a new one.
style → component visual treatment (e.g. nova, vega).
base → primitive library (radix or base). Affects component APIs and available props.
iconLibrary → determines icon imports. Use lucide-react for lucide, @tabler/icons-react for tabler, etc. Never assume lucide-react.
resolvedPaths → exact file-system destinations for components, utils, hooks, etc.
framework → routing and file conventions (e.g. Next.js App Router vs Vite SPA).
packageManager → use this for any non-shadcn dependency installs (e.g. pnpm add date-fns vs npm install_date-fns).
See cli.md — info command for the full field reference.
Component Docs, Examples, and Usage
Run npx shadcn@latest docs <component> to get the URLs for a component's documentation, examples, and API reference. Fetch these URLs to get the actual content.
npx shadcn@latest docs button dialog select
When creating, fixing, debugging, or using a component, always run npx shadcn@latest docs and fetch the URLs first. This ensures you're working with the correct API and usage patterns rather than guessing.
Workflow
- Get project context — already injected above. Run
npx shadcn@latest info again if you need to refresh.
- Check installed components first — before running
add, always check the components list from project context or list the resolvedPaths.ui directory. Don't import components that haven't been added, and don't re-add ones already installed.
- Map the surface to a recipe before coding. Decide which installed primitives should make up the screen. Prefer a composition plan such as
Card + Tabs + ScrollArea + Dialog over freehand markup.
- Find missing components only after checking installed ones —
npx shadcn@latest search.
- Get docs and examples — run
npx shadcn@latest docs <component> to get URLs, then fetch them. Use npx shadcn@latest view to browse registry items you haven't installed. To preview changes to installed components, use npx shadcn@latest add --diff.
- Install or update —
npx shadcn@latest add. When updating existing components, use --dry-run and --diff to preview changes first (see Updating Components below).
- Fix imports in third-party components — After adding components from community registries (e.g.
@bundui, @magicui), check the added non-UI files for hardcoded import paths like @/components/ui/.... These won't match the project's actual aliases. Use npx shadcn@latest info to get the correct ui alias (e.g. @workspace/ui/components) and rewrite the imports accordingly. The CLI rewrites imports for its own UI files, but third-party registry components may use default paths that don't match the project.
- Review added components — After adding a component or block from any registry, always read the added files and verify they are correct. Check for missing sub-components (e.g.
SelectItem without SelectGroup), missing imports, incorrect composition, or violations of the Critical Rules. Also replace any icon imports with the project's iconLibrary from the project context (e.g. if the registry item uses lucide-react but the project uses hugeicons, swap the imports and icon names accordingly). Fix all issues before moving on.
- Registry must be explicit — When the user asks to add a block or component, do not guess the registry. If no registry is specified (e.g. user says "add a login block" without specifying
@shadcn, @tailark, etc.), ask which registry to use. Never default to a registry on behalf of the user.
- Switching presets — Ask the user first: reinstall, merge, or skip?
- Reinstall:
npx shadcn@latest init --preset <code> --force --reinstall. Overwrites all components.
- Merge:
npx shadcn@latest init --preset <code> --force --no-reinstall, then run npx shadcn@latest info to list installed components, then for each installed component use --dry-run and --diff to smart merge it individually.
- Skip:
npx shadcn@latest init --preset <code> --force --no-reinstall. Only updates config and CSS, leaves components as-is.
Updating Components
When the user asks to update a component from upstream while keeping their local changes, use --dry-run and --diff to intelligently merge. NEVER fetch raw files from GitHub manually — always use the CLI.
- Run
npx shadcn@latest add <component> --dry-run to see all files that would be affected.
- For each file, run
npx shadcn@latest add <component> --diff <file> to see what changed upstream vs local.
- Decide per file based on the diff:
- No local changes → safe to overwrite.
- Has local changes → read the local file, analyze the diff, and apply upstream updates while preserving local modifications.
- User says "just update everything" → use
--overwrite, but confirm first.
- Never use
--overwrite without the user's explicit approval.
Quick Reference
# Create a new project.
npx shadcn@latest init --name my-app --preset base-nova
npx shadcn@latest init --name my-app --preset a2r6bw --template vite
# Create a monorepo project.
npx shadcn@latest init --name my-app --preset base-nova --monorepo
npx shadcn@latest init --name my-app --preset base-nova --template next --monorepo
# Initialize existing project.
npx shadcn@latest init --preset base-nova
npx shadcn@latest init --defaults # shortcut: --template=next --preset=base-nova
# Add components.
npx shadcn@latest add button card dialog
npx shadcn@latest add @magicui/shimmer-button
npx shadcn@latest add --all
# Preview changes before adding/updating.
npx shadcn@latest add button --dry-run
npx shadcn@latest add button --diff button.tsx
npx shadcn@latest add @acme/form --view button.tsx
# Search registries.
npx shadcn@latest search @shadcn -q "sidebar"
npx shadcn@latest search @tailark -q "stats"
# Get component docs and example URLs.
npx shadcn@latest docs button dialog select
# View registry item details (for items not yet installed).
npx shadcn@latest view @shadcn/button
Named presets: base-nova, radix-nova
Templates: next, vite, start, react-router, astro (all support --monorepo) and laravel (not supported for monorepo)
Preset codes: Base62 strings starting with a (e.g. a2r6bw), from ui.shadcn.com.
Detailed References
- rules/forms.md — FieldGroup, Field, InputGroup, ToggleGroup, FieldSet, validation states
- rules/composition.md — Groups, overlays, Card, Tabs, Avatar, Alert, Empty, Toast, Separator, Skeleton, Badge, Button loading
- rules/icons.md — data-icon, icon sizing, passing icons as objects
- rules/styling.md — Semantic colors, variants, className, spacing, size, truncate, dark mode, cn(), z-index
- rules/base-vs-radix.md — asChild vs render, Select, ToggleGroup, Slider, Accordion
- cli.md — Commands, flags, presets, templates
- customization.md — Theming, CSS variables, extending components
1---2name: shadcn-33description: Manages shadcn components and projects — adding, searching, fixing, debugging, styling, and composing UI. Provides project context, component docs, and usage examples. Applies when working with shadcn/ui, component registries, presets, --preset codes, or any project with a components.json file. Also triggers for "shadcn init", "create an app with --preset", or "switch to --preset".4---5
6# shadcn/ui
7
8A framework for building ui, components and design systems. Components are added as source code to the user's project via the CLI.
9
10## AI-Driven Workflow (Vibe Coding)
11
12When working as an AI assistant, follow this "Vibe Coding" workflow. The user focuses on the "vibe" and "vision," while the AI handles the technical execution via the CLI.
13
141. **Direct Execution**: When a user asks for UI (e.g., "Add a login form", "Create a dashboard"), do not just provide code. Use the `npx shadcn@latest add` command directly in the terminal to install dependencies and source code.
152. **Context Alignment**: Always check `npx shadcn@latest info --json` to ensure you are using the correct framework, aliases, and icon libraries.
163. **Prompt-to-CLI Mapping**:
17 - _"Add a login form..."_ -> `npx shadcn@latest add form input button`
18 - _"Create a settings page..."_ -> `npx shadcn@latest add tabs card form`
19 - _"Build a dashboard..."_ -> `npx shadcn@latest add sidebar table chart`
20 - _"Switch to --preset [CODE]"_ -> `npx shadcn@latest init --preset [CODE] --force`
21 - _"Can you add a hero from @tailark?"_ -> `npx shadcn@latest add @tailark/hero`
224. **Composition over Snippets**: After adding primitives via CLI, compose the final UI in the target file using the project's established patterns (e.g., `FieldGroup`, `SectionShell`).
235. **Proactive Discovery**: Use `npx shadcn@latest search` or `docs` to find the best components for the user's request before asking for clarification.
24
25> **IMPORTANT:** Run all CLI commands using the project's package runner: `npx shadcn@latest`, `pnpm dlx shadcn@latest`, or `bunx --bun shadcn@latest` — based on the project's `packageManager`. Examples below use `npx shadcn@latest` but substitute the correct runner for the project.
26
27## Current Project Context
28
29```json
30!`npx shadcn@latest info --json 2>/dev/null || echo '{"error": "No shadcn project found. Run shadcn init first."}'`
31```
32
33The JSON above contains the project config and installed components. Use `npx shadcn@latest docs <component>` to get documentation and example URLs for any component.
34
35## Principles
36
371. **Use existing components first.** Use `npx shadcn@latest search` to check registries before writing custom UI. Check community registries too.
382. **Compose, don't reinvent.** Settings page = Tabs + Card + form controls. Dashboard = Sidebar + Card + Chart + Table.
393. **Use built-in variants before custom styles.** `variant="outline"`, `size="sm"`, etc.
404. **Use semantic colors.** `bg-primary`, `text-muted-foreground` — never raw values like `bg-blue-500`.
41
42## Component-First Mandate
43
44When working in a project that already has a populated `components/ui` directory, treat shadcn as a **component composition system**, not a styling suggestion.
45
461. **Maximise reuse of installed primitives.** If the UI can reasonably be expressed with existing shadcn components, do that before writing custom markup.
472. **Prefer richer composition over plain wrappers.** A good shadcn screen should usually contain several cooperating primitives: `Card` + `Tabs` + `ScrollArea`, `Dialog` + `Form` + `Button`, `Popover` + `Command`, etc.
483. **Avoid browser-native UI** for app interactions when a local shadcn primitive exists.
49 - `window.prompt` → `Dialog` + `Input`/`Textarea`
50 - `window.confirm` → `AlertDialog`
51 - ad hoc tooltips/help bubbles → `Tooltip`, `HoverCard`, or `Popover`
524. **Do not default to raw `div` + border + padding** for panels, menus, empty states, sidebars, or overlays. Reach for a component recipe first.
535. **Use multiple components when the surface benefits from structure.** The goal is not fewer imports; the goal is a better-composed interface.
54
55## Current Project Inventory
56
57For this PMTL_VN repo, the installed local shadcn/radix primitives include:
58
59- Core structure: `card`, `separator`, `resizable`, `scroll-area`, `collapsible`, `accordion`, `tabs`, `sidebar`, `sheet`, `drawer`
60- Actions and feedback: `button`, `badge`, `alert`, `alert-dialog`, `sonner`, `progress`, `skeleton`
61- Inputs and forms: `form`, `input`, `textarea`, `select`, `switch`, `checkbox`, `radio-group`, `toggle`, `toggle-group`, `slider`, `input-otp`, `calendar`
62- Navigation: `breadcrumb`, `navigation-menu`, `menubar`, `pagination`, `command`
63- Overlays and detail affordances: `dialog`, `popover`, `hover-card`, `tooltip`, `dropdown-menu`, `context-menu`
64- Data display: `avatar`, `table`, `chart`, `carousel`, `aspect-ratio`
65- Local project extras: `feature-card`, `section-shell`
66
67Because this project uses `base: radix`, these components are already enough to build most interface patterns without inventing custom wrappers.
68
69## Preferred Recipes
70
71When generating or editing UI, prefer these recipes by default:
72
73- Page shell: `SectionShell` or layout container + `Breadcrumb` + `Card`
74- Reading/detail page: `Card` + `Badge` + `ScrollArea` + `Tabs`/`Collapsible` + `Popover`/`HoverCard`
75- Dense sidebar: `Card` + `ScrollArea` + `Collapsible` + `Button` + `Badge`
76- Search/filter panel: `Input` + `Select` + `ToggleGroup` + `Badge` + `Popover`/`Command`
77- Modal workflow: `Dialog` + `DialogHeader` + `Form` + `Button`
78- Dangerous action: `AlertDialog`
79- Inline status/info: `Alert`, `Badge`, `Tooltip`
80- Long lists: `ScrollArea` + `Card` or `Table`
81- Stepper/sectioned content: `Tabs`, `Accordion`, or `Collapsible`
82- Metrics/dashboard: `Card` + `Chart` + `Progress` + `Badge`
83- Media display: `AspectRatio` + `Carousel`
84
85## Diversity Heuristic
86
87When a user asks for "đẹp", "xịn", "đa dạng", "radix-like", or a premium UI, bias toward **using more of the right primitives together**, not toward custom ornament.
88
89- Good: `CardHeader`, `CardContent`, `Badge`, `Separator`, `ScrollArea`, `Dialog`, `HoverCard`, `Tooltip`
90- Weak: one big `div` with manual padding/border and a few styled buttons
91
92Use this rule of thumb:
93
94- If a screen has 3 or more distinct interaction zones, it should usually use at least 3 different shadcn primitives.
95- If a screen has an action that opens, reveals, filters, confirms, or annotates something, it should usually use the corresponding overlay/disclosure primitive instead of custom stateful markup.
96- If the layout feels visually flat, increase structure with composition (`CardHeader`, `CardDescription`, `Separator`, grouped `Badge`s, `ScrollArea`) before adding decorative CSS.
97
98## Critical Rules
99
100These rules are **always enforced**. Each links to a file with Incorrect/Correct code pairs.
101
102### Styling & Tailwind → [styling.md](./rules/styling.md)
103
104- **`className` for layout, not styling.** Never override component colors or typography.
105- **No `space-x-*` or `space-y-*`.** Use `flex` with `gap-*`. For vertical stacks, `flex flex-col gap-*`.
106- **Use `size-*` when width and height are equal.** `size-10` not `w-10 h-10`.
107- **Use `truncate` shorthand.** Not `overflow-hidden text-ellipsis whitespace-nowrap`.
108- **No manual `dark:` color overrides.** Use semantic tokens (`bg-background`, `text-muted-foreground`).
109- **Use `cn()` for conditional classes.** Don't write manual template literal ternaries.
110- **No manual `z-index` on overlay components.** Dialog, Sheet, Popover, etc. handle their own stacking.
111
112### Forms & Inputs → [forms.md](./rules/forms.md)
113
114- **Forms use `FieldGroup` + `Field`.** Never use raw `div` with `space-y-*` or `grid gap-*` for form layout.
115- **`InputGroup` uses `InputGroupInput`/`InputGroupTextarea`.** Never raw `Input`/`Textarea` inside `InputGroup`.
116- **Buttons inside inputs use `InputGroup` + `InputGroupAddon`.**
117- **Option sets (2–7 choices) use `ToggleGroup`.** Don't loop `Button` with manual active state.
118- **`FieldSet` + `FieldLegend` for grouping related checkboxes/radios.** Don't use a `div` with a heading.
119- **Field validation uses `data-invalid` + `aria-invalid`.** `data-invalid` on `Field`, `aria-invalid` on the control. For disabled: `data-disabled` on `Field`, `disabled` on the control.
120
121### Component Structure → [composition.md](./rules/composition.md)
122
123- **Items always inside their Group.** `SelectItem` → `SelectGroup`. `DropdownMenuItem` → `DropdownMenuGroup`. `CommandItem` → `CommandGroup`.
124- **Use `asChild` (radix) or `render` (base) for custom triggers.** Check `base` field from `npx shadcn@latest info`. → [base-vs-radix.md](./rules/base-vs-radix.md)
125- **Dialog, Sheet, and Drawer always need a Title.** `DialogTitle`, `SheetTitle`, `DrawerTitle` required for accessibility. Use `className="sr-only"` if visually hidden.
126- **Use full Card composition.** `CardHeader`/`CardTitle`/`CardDescription`/`CardContent`/`CardFooter`. Don't dump everything in `CardContent`.
127- **Button has no `isPending`/`isLoading`.** Compose with `Spinner` + `data-icon` + `disabled`.
128- **`TabsTrigger` must be inside `TabsList`.** Never render triggers directly in `Tabs`.
129- **`Avatar` always needs `AvatarFallback`.** For when the image fails to load.
130
131### Use Components, Not Custom Markup → [composition.md](./rules/composition.md)
132
133- **Use existing components before custom markup.** Check if a component exists before writing a styled `div`.
134- **Callouts use `Alert`.** Don't build custom styled divs.
135- **Empty states use `Empty`.** Don't build custom empty state markup.
136- **Toast via `sonner`.** Use `toast()` from `sonner`.
137- **Use `Separator`** instead of `<hr>` or `<div className="border-t">`.
138- **Use `Skeleton`** for loading placeholders. No custom `animate-pulse` divs.
139- **Use `Badge`** instead of custom styled spans.
140- **Use `Dialog`/`Sheet`/`Drawer`/`AlertDialog` instead of browser-native prompt/confirm flows.**
141- **Use `ScrollArea` for constrained panels and sidebars** instead of raw overflowing containers when the list can grow.
142- **Use `CardHeader`/`CardDescription`/`CardContent` to create hierarchy** before adding custom wrappers inside cards.
143
144### Icons → [icons.md](./rules/icons.md)
145
146- **Icons in `Button` use `data-icon`.** `data-icon="inline-start"` or `data-icon="inline-end"` on the icon.
147- **No sizing classes on icons inside components.** Components handle icon sizing via CSS. No `size-4` or `w-4 h-4`.
148- **Pass icons as objects, not string keys.** `icon={CheckIcon}`, not a string lookup.
149
150### CLI
151
152- **Never decode or fetch preset codes manually.** Pass them directly to `npx shadcn@latest init --preset <code>`.
153
154## Key Patterns
155
156These are the most common patterns that differentiate correct shadcn/ui code. For edge cases, see the linked rule files above.
157
158```tsx
159// Form layout: FieldGroup + Field, not div + Label.
160<FieldGroup>
161 <Field>
162 <FieldLabel htmlFor="email">Email</FieldLabel>
163 <Input id="email" />
164 </Field>
165</FieldGroup>
166
167// Validation: data-invalid on Field, aria-invalid on the control.
168<Field data-invalid>
169 <FieldLabel>Email</FieldLabel>
170 <Input aria-invalid />
171 <FieldDescription>Invalid email.</FieldDescription>
172</Field>
173
174// Icons in buttons: data-icon, no sizing classes.
175<Button>
176 <SearchIcon data-icon="inline-start" />
177 Search
178</Button>
179
180// Spacing: gap-*, not space-y-*.
181<div className="flex flex-col gap-4"> // correct
182<div className="space-y-4"> // wrong
183
184// Equal dimensions: size-*, not w-* h-*.
185<Avatar className="size-10"> // correct
186<Avatar className="w-10 h-10"> // wrong
187
188// Status colors: Badge variants or semantic tokens, not raw colors.
189<Badge variant="secondary">+20.1%</Badge> // correct
190<span className="text-emerald-600">+20.1%</span> // wrong
191```
192
193## Component Selection
194
195| Need | Use |
196| -------------------------- | --------------------------------------------------------------------------------------------------- |
197| Button/action | `Button` with appropriate variant |
198| Form inputs | `Input`, `Select`, `Combobox`, `Switch`, `Checkbox`, `RadioGroup`, `Textarea`, `InputOTP`, `Slider` |
199| Toggle between 2–5 options | `ToggleGroup` + `ToggleGroupItem` |
200| Data display | `Table`, `Card`, `Badge`, `Avatar` |
201| Navigation | `Sidebar`, `NavigationMenu`, `Breadcrumb`, `Tabs`, `Pagination` |
202| Overlays | `Dialog` (modal), `Sheet` (side panel), `Drawer` (bottom sheet), `AlertDialog` (confirmation) |
203| Feedback | `sonner` (toast), `Alert`, `Progress`, `Skeleton`, `Spinner` |
204| Command palette | `Command` inside `Dialog` |
205| Charts | `Chart` (wraps Recharts) |
206| Layout | `Card`, `Separator`, `Resizable`, `ScrollArea`, `Accordion`, `Collapsible` |
207| Empty states | `Empty` |
208| Menus | `DropdownMenu`, `ContextMenu`, `Menubar` |
209| Tooltips/info | `Tooltip`, `HoverCard`, `Popover` |
210
211## Key Fields
212
213The injected project context contains these key fields:
214
215- **`aliases`** → use the actual alias prefix for imports (e.g. `@/`, `~/`), never hardcode.
216- **`isRSC`** → when `true`, components using `useState`, `useEffect`, event handlers, or browser APIs need `"use client"` at the top of the file. Always reference this field when advising on the directive.
217- **`tailwindVersion`** → `"v4"` uses `@theme inline` blocks; `"v3"` uses `tailwind.config.js`.
218- **`tailwindCssFile`** → the global CSS file where custom CSS variables are defined. Always edit this file, never create a new one.
219- **`style`** → component visual treatment (e.g. `nova`, `vega`).
220- **`base`** → primitive library (`radix` or `base`). Affects component APIs and available props.
221- **`iconLibrary`** → determines icon imports. Use `lucide-react` for `lucide`, `@tabler/icons-react` for `tabler`, etc. Never assume `lucide-react`.
222- **`resolvedPaths`** → exact file-system destinations for components, utils, hooks, etc.
223- **`framework`** → routing and file conventions (e.g. Next.js App Router vs Vite SPA).
224- **`packageManager`** → use this for any non-shadcn dependency installs (e.g. `pnpm add date-fns` vs `npm install_date-fns`).
225
226See [cli.md — `info` command](./cli.md) for the full field reference.
227
228## Component Docs, Examples, and Usage
229
230Run `npx shadcn@latest docs <component>` to get the URLs for a component's documentation, examples, and API reference. Fetch these URLs to get the actual content.
231
232```bash
233npx shadcn@latest docs button dialog select
234```
235
236**When creating, fixing, debugging, or using a component, always run `npx shadcn@latest docs` and fetch the URLs first.** This ensures you're working with the correct API and usage patterns rather than guessing.
237
238## Workflow
239
2401. **Get project context** — already injected above. Run `npx shadcn@latest info` again if you need to refresh.
2412. **Check installed components first** — before running `add`, always check the `components` list from project context or list the `resolvedPaths.ui` directory. Don't import components that haven't been added, and don't re-add ones already installed.
2423. **Map the surface to a recipe before coding.** Decide which installed primitives should make up the screen. Prefer a composition plan such as `Card + Tabs + ScrollArea + Dialog` over freehand markup.
2434. **Find missing components only after checking installed ones** — `npx shadcn@latest search`.
2445. **Get docs and examples** — run `npx shadcn@latest docs <component>` to get URLs, then fetch them. Use `npx shadcn@latest view` to browse registry items you haven't installed. To preview changes to installed components, use `npx shadcn@latest add --diff`.
2456. **Install or update** — `npx shadcn@latest add`. When updating existing components, use `--dry-run` and `--diff` to preview changes first (see [Updating Components](#updating-components) below).
2467. **Fix imports in third-party components** — After adding components from community registries (e.g. `@bundui`, `@magicui`), check the added non-UI files for hardcoded import paths like `@/components/ui/...`. These won't match the project's actual aliases. Use `npx shadcn@latest info` to get the correct `ui` alias (e.g. `@workspace/ui/components`) and rewrite the imports accordingly. The CLI rewrites imports for its own UI files, but third-party registry components may use default paths that don't match the project.
2478. **Review added components** — After adding a component or block from any registry, **always read the added files and verify they are correct**. Check for missing sub-components (e.g. `SelectItem` without `SelectGroup`), missing imports, incorrect composition, or violations of the [Critical Rules](#critical-rules). Also replace any icon imports with the project's `iconLibrary` from the project context (e.g. if the registry item uses `lucide-react` but the project uses `hugeicons`, swap the imports and icon names accordingly). Fix all issues before moving on.
2489. **Registry must be explicit** — When the user asks to add a block or component, **do not guess the registry**. If no registry is specified (e.g. user says "add a login block" without specifying `@shadcn`, `@tailark`, etc.), ask which registry to use. Never default to a registry on behalf of the user.
24910. **Switching presets** — Ask the user first: **reinstall**, **merge**, or **skip**?
250 - **Reinstall**: `npx shadcn@latest init --preset <code> --force --reinstall`. Overwrites all components.
251 - **Merge**: `npx shadcn@latest init --preset <code> --force --no-reinstall`, then run `npx shadcn@latest info` to list installed components, then for each installed component use `--dry-run` and `--diff` to [smart merge](#updating-components) it individually.
252 - **Skip**: `npx shadcn@latest init --preset <code> --force --no-reinstall`. Only updates config and CSS, leaves components as-is.
253
254## Updating Components
255
256When the user asks to update a component from upstream while keeping their local changes, use `--dry-run` and `--diff` to intelligently merge. **NEVER fetch raw files from GitHub manually — always use the CLI.**
257
2581. Run `npx shadcn@latest add <component> --dry-run` to see all files that would be affected.
2592. For each file, run `npx shadcn@latest add <component> --diff <file>` to see what changed upstream vs local.
2603. Decide per file based on the diff:
261 - No local changes → safe to overwrite.
262 - Has local changes → read the local file, analyze the diff, and apply upstream updates while preserving local modifications.
263 - User says "just update everything" → use `--overwrite`, but confirm first.
2644. **Never use `--overwrite` without the user's explicit approval.**
265
266## Quick Reference
267
268```bash
269# Create a new project.
270npx shadcn@latest init --name my-app --preset base-nova
271npx shadcn@latest init --name my-app --preset a2r6bw --template vite
272
273# Create a monorepo project.
274npx shadcn@latest init --name my-app --preset base-nova --monorepo
275npx shadcn@latest init --name my-app --preset base-nova --template next --monorepo
276
277# Initialize existing project.
278npx shadcn@latest init --preset base-nova
279npx shadcn@latest init --defaults # shortcut: --template=next --preset=base-nova
280
281# Add components.
282npx shadcn@latest add button card dialog
283npx shadcn@latest add @magicui/shimmer-button
284npx shadcn@latest add --all
285
286# Preview changes before adding/updating.
287npx shadcn@latest add button --dry-run
288npx shadcn@latest add button --diff button.tsx
289npx shadcn@latest add @acme/form --view button.tsx
290
291# Search registries.
292npx shadcn@latest search @shadcn -q "sidebar"
293npx shadcn@latest search @tailark -q "stats"
294
295# Get component docs and example URLs.
296npx shadcn@latest docs button dialog select
297
298# View registry item details (for items not yet installed).
299npx shadcn@latest view @shadcn/button
300```
301
302**Named presets:** `base-nova`, `radix-nova`
303**Templates:** `next`, `vite`, `start`, `react-router`, `astro` (all support `--monorepo`) and `laravel` (not supported for monorepo)
304**Preset codes:** Base62 strings starting with `a` (e.g. `a2r6bw`), from [ui.shadcn.com](https://ui.shadcn.com).
305
306## Detailed References
307
308- [rules/forms.md](./rules/forms.md) — FieldGroup, Field, InputGroup, ToggleGroup, FieldSet, validation states
309- [rules/composition.md](./rules/composition.md) — Groups, overlays, Card, Tabs, Avatar, Alert, Empty, Toast, Separator, Skeleton, Badge, Button loading
310- [rules/icons.md](./rules/icons.md) — data-icon, icon sizing, passing icons as objects
311- [rules/styling.md](./rules/styling.md) — Semantic colors, variants, className, spacing, size, truncate, dark mode, cn(), z-index
312- [rules/base-vs-radix.md](./rules/base-vs-radix.md) — asChild vs render, Select, ToggleGroup, Slider, Accordion
313- [cli.md](./cli.md) — Commands, flags, presets, templates
314- [customization.md](./customization.md) — Theming, CSS variables, extending components