···11---
22name: shadcn
33-description: 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".
33+description: Manages shadcn components and projects. Add, search, fix, debug, style, and compose UI. Use for shadcn/ui, registry items, presets, `--preset` codes, or any project with `components.json`. Also applies to `shadcn init`, `create an app with --preset`, and `switch to --preset`.
44user-invocable: false
55allowed-tools: Bash(npx shadcn@latest *), Bash(pnpm dlx shadcn@latest *), Bash(bunx --bun shadcn@latest *)
66---
7788# shadcn/ui
991010-A framework for building ui, components and design systems. Components are added as source code to the user's project via the CLI.
1010+A UI framework for components and design systems. The CLI adds source code to the user's project.
11111212-> **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.
1212+> **IMPORTANT:** Run CLI commands with the project's package runner: `npx shadcn@latest`, `pnpm dlx shadcn@latest`, or `bunx --bun shadcn@latest`, based on `packageManager`. Examples use `npx shadcn@latest`; swap to the project runner.
13131414## Current Project Context
1515···1717!`npx shadcn@latest info --json`
1818```
19192020-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.
2020+Use the JSON for project config and installed components. Run `npx shadcn@latest docs <component>` for docs and example URLs.
21212222## Principles
23232424-1. **Use existing components first.** Use `npx shadcn@latest search` to check registries before writing custom UI. Check community registries too.
2525-2. **Compose, don't reinvent.** Settings page = Tabs + Card + form controls. Dashboard = Sidebar + Card + Chart + Table.
2626-3. **Use built-in variants before custom styles.** `variant="outline"`, `size="sm"`, etc.
2727-4. **Use semantic colors.** `bg-primary`, `text-muted-foreground` — never raw values like `bg-blue-500`.
2424+1. Use existing components first. Run `npx shadcn@latest search` before custom UI. Check community registries too.
2525+2. Compose, don't reinvent. Settings page = Tabs + Card + form controls. Dashboard = Sidebar + Card + Chart + Table.
2626+3. Use built-in variants before custom styles. `variant="outline"`, `size="sm"`, etc.
2727+4. Use semantic colors. `bg-primary`, `text-muted-foreground` only. No raw values like `bg-blue-500`.
28282929## Critical Rules
30303131-These rules are **always enforced**. Each links to a file with Incorrect/Correct code pairs.
3131+These rules are always on. Each links to incorrect and correct examples.
32323333### Styling & Tailwind → [styling.md](./rules/styling.md)
34343535-- **`className` for layout, not styling.** Never override component colors or typography.
3636-- **No `space-x-*` or `space-y-*`.** Use `flex` with `gap-*`. For vertical stacks, `flex flex-col gap-*`.
3737-- **Use `size-*` when width and height are equal.** `size-10` not `w-10 h-10`.
3838-- **Use `truncate` shorthand.** Not `overflow-hidden text-ellipsis whitespace-nowrap`.
3939-- **No manual `dark:` color overrides.** Use semantic tokens (`bg-background`, `text-muted-foreground`).
4040-- **Use `cn()` for conditional classes.** Don't write manual template literal ternaries.
4141-- **No manual `z-index` on overlay components.** Dialog, Sheet, Popover, etc. handle their own stacking.
3535+- `className` for layout, not styling. Do not override component colors or typography.
3636+- No `space-x-*` or `space-y-*`. Use `flex` with `gap-*`. For vertical stacks, use `flex flex-col gap-*`.
3737+- Use `size-*` when width and height match. `size-10`, not `w-10 h-10`.
3838+- Use `truncate`. Do not write `overflow-hidden text-ellipsis whitespace-nowrap`.
3939+- No manual `dark:` color overrides. Use semantic tokens like `bg-background` and `text-muted-foreground`.
4040+- Use `cn()` for conditional classes. Do not write manual template ternaries.
4141+- No manual `z-index` on overlay components. Dialog, Sheet, Popover, and similar handle stacking.
42424343### Forms & Inputs → [forms.md](./rules/forms.md)
44444545-- **Forms use `FieldGroup` + `Field`.** Never use raw `div` with `space-y-*` or `grid gap-*` for form layout.
4646-- **`InputGroup` uses `InputGroupInput`/`InputGroupTextarea`.** Never raw `Input`/`Textarea` inside `InputGroup`.
4747-- **Buttons inside inputs use `InputGroup` + `InputGroupAddon`.**
4848-- **Option sets (2–7 choices) use `ToggleGroup`.** Don't loop `Button` with manual active state.
4949-- **`FieldSet` + `FieldLegend` for grouping related checkboxes/radios.** Don't use a `div` with a heading.
5050-- **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.
4545+- Forms use `FieldGroup` + `Field`. Do not use raw `div` with `space-y-*` or `grid gap-*` for form layout.
4646+- `InputGroup` uses `InputGroupInput` and `InputGroupTextarea`. Do not place raw `Input` or `Textarea` inside `InputGroup`.
4747+- Buttons inside inputs use `InputGroup` + `InputGroupAddon`.
4848+- Option sets with 2 to 7 choices use `ToggleGroup`. Do not loop `Button` with manual active state.
4949+- Use `FieldSet` + `FieldLegend` for related checkboxes and radios. Do not use a `div` with a heading.
5050+- Validation uses `data-invalid` on `Field` and `aria-invalid` on the control. For disabled, use `data-disabled` on `Field` and `disabled` on the control.
51515252### Component Structure → [composition.md](./rules/composition.md)
53535454-- **Items always inside their Group.** `SelectItem` → `SelectGroup`. `DropdownMenuItem` → `DropdownMenuGroup`. `CommandItem` → `CommandGroup`.
5555-- **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)
5656-- **Dialog, Sheet, and Drawer always need a Title.** `DialogTitle`, `SheetTitle`, `DrawerTitle` required for accessibility. Use `className="sr-only"` if visually hidden.
5757-- **Use full Card composition.** `CardHeader`/`CardTitle`/`CardDescription`/`CardContent`/`CardFooter`. Don't dump everything in `CardContent`.
5858-- **Button has no `isPending`/`isLoading`.** Compose with `Spinner` + `data-icon` + `disabled`.
5959-- **`TabsTrigger` must be inside `TabsList`.** Never render triggers directly in `Tabs`.
6060-- **`Avatar` always needs `AvatarFallback`.** For when the image fails to load.
5454+- Items stay inside their group. `SelectItem` → `SelectGroup`. `DropdownMenuItem` → `DropdownMenuGroup`. `CommandItem` → `CommandGroup`.
5555+- Use `asChild` for radix or `render` for base when making custom triggers. Check `base` in `npx shadcn@latest info`. → [base-vs-radix.md](./rules/base-vs-radix.md)
5656+- Dialog, Sheet, and Drawer need a Title. Use `DialogTitle`, `SheetTitle`, or `DrawerTitle`. Hide with `className="sr-only"` if needed.
5757+- Use full Card composition: `CardHeader`, `CardTitle`, `CardDescription`, `CardContent`, `CardFooter`.
5858+- Button has no `isPending` or `isLoading`. Compose with `Spinner` + `data-icon` + `disabled`.
5959+- `TabsTrigger` must stay inside `TabsList`.
6060+- `Avatar` needs `AvatarFallback`.
61616262### Use Components, Not Custom Markup → [composition.md](./rules/composition.md)
63636464-- **Use existing components before custom markup.** Check if a component exists before writing a styled `div`.
6565-- **Callouts use `Alert`.** Don't build custom styled divs.
6666-- **Empty states use `Empty`.** Don't build custom empty state markup.
6767-- **Toast via `sonner`.** Use `toast()` from `sonner`.
6868-- **Use `Separator`** instead of `<hr>` or `<div className="border-t">`.
6969-- **Use `Skeleton`** for loading placeholders. No custom `animate-pulse` divs.
7070-- **Use `Badge`** instead of custom styled spans.
6464+- Use existing components before custom markup. Check if a component exists before writing a styled `div`.
6565+- Callouts use `Alert`.
6666+- Empty states use `Empty`.
6767+- Toasts use `sonner` and `toast()`.
6868+- Use `Separator` instead of `<hr>` or `<div className="border-t">`.
6969+- Use `Skeleton` for loading placeholders. No custom `animate-pulse` divs.
7070+- Use `Badge` instead of custom styled spans.
71717272### Icons → [icons.md](./rules/icons.md)
73737474-- **Icons in `Button` use `data-icon`.** `data-icon="inline-start"` or `data-icon="inline-end"` on the icon.
7575-- **No sizing classes on icons inside components.** Components handle icon sizing via CSS. No `size-4` or `w-4 h-4`.
7676-- **Pass icons as objects, not string keys.** `icon={CheckIcon}`, not a string lookup.
7474+- Icons in `Button` use `data-icon`, either `inline-start` or `inline-end`.
7575+- Do not size icons inside components. Components handle icon sizing. No `size-4` or `w-4 h-4`.
7676+- Pass icons as objects, not string keys. `icon={CheckIcon}`, not a string lookup.
77777878### CLI
79798080-- **Never decode preset codes or build preset URLs manually.** Use `npx shadcn@latest preset decode <code>`, `preset url <code>`, or `preset open <code>`. For project-aware preset detection, use `npx shadcn@latest preset resolve`.
8181-- **Apply preset codes directly with the CLI.** Use `npx shadcn@latest apply <code>` for existing projects, or `npx shadcn@latest init --preset <code>` when initializing.
8080+- Never decode preset codes or build preset URLs manually. Use `preset decode`, `preset url`, or `preset open`. For project-aware detection, use `preset resolve`.
8181+- Apply preset codes directly with the CLI. Use `apply <code>` for existing projects, or `init --preset <code>` when initializing.
82828383## Key Patterns
8484-8585-These are the most common patterns that differentiate correct shadcn/ui code. For edge cases, see the linked rule files above.
86848785```tsx
8886// Form layout: FieldGroup + Field, not div + Label.
···139137140138## Key Fields
141139142142-The injected project context contains these key fields:
140140+Injected project context fields:
143141144144-- **`aliases`** → use the actual alias prefix for imports (e.g. `@/`, `~/`), never hardcode.
145145-- **`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.
146146-- **`tailwindVersion`** → `"v4"` uses `@theme inline` blocks; `"v3"` uses `tailwind.config.js`.
147147-- **`tailwindCssFile`** → the global CSS file where custom CSS variables are defined. Always edit this file, never create a new one.
148148-- **`style`** → component visual treatment (e.g. `nova`, `vega`).
149149-- **`base`** → primitive library (`radix` or `base`). Affects component APIs and available props.
150150-- **`iconLibrary`** → determines icon imports. Use `lucide-react` for `lucide`, `@tabler/icons-react` for `tabler`, etc. Never assume `lucide-react`.
151151-- **`resolvedPaths`** → exact file-system destinations for components, utils, hooks, etc.
152152-- **`framework`** → routing and file conventions (e.g. Next.js App Router vs Vite SPA).
153153-- **`packageManager`** → use this for any non-shadcn dependency installs (e.g. `pnpm add date-fns` vs `npm install date-fns`).
154154-- **`preset`** → resolved preset code and values for the current project. Use `npx shadcn@latest preset resolve --json` when you only need preset information.
142142+- `aliases` means use the real alias prefix for imports, never hardcode.
143143+- `isRSC` means components with `useState`, `useEffect`, handlers, or browser APIs need `"use client"`.
144144+- `tailwindVersion` means `v4` uses `@theme inline` and `v3` uses `tailwind.config.js`.
145145+- `tailwindCssFile` is the global CSS file for custom CSS variables. Edit this file, never create a new one.
146146+- `style` is the component visual treatment, like `nova` or `vega`.
147147+- `base` is the primitive library, `radix` or `base`. It affects APIs and props.
148148+- `iconLibrary` controls icon imports. Use `lucide-react` for `lucide`, `@tabler/icons-react` for `tabler`, and so on.
149149+- `resolvedPaths` gives exact file destinations for components, utils, hooks, and more.
150150+- `framework` covers routing and file conventions, such as Next.js App Router or Vite SPA.
151151+- `packageManager` is the runner for non-shadcn installs, such as `pnpm add date-fns`.
152152+- `preset` is the resolved preset code and values for the current project. Use `preset resolve --json` for details.
155153156154See [cli.md — `info` command](./cli.md) for the full field reference.
157155158156## Component Docs, Examples, and Usage
159157160160-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.
158158+Run `npx shadcn@latest docs <component>` to get docs, examples, and API URLs. Fetch those URLs for actual content.
161159162160```bash
163161npx shadcn@latest docs button dialog select
164162```
165163166166-**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.
164164+When creating, fixing, debugging, or using a component, always run `npx shadcn@latest docs` and fetch the URLs first. That keeps API usage correct.
167165168166## Workflow
169167170170-1. **Get project context** — already injected above. Run `npx shadcn@latest info` again if you need to refresh.
171171-2. **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.
172172-3. **Find components** — `npx shadcn@latest search`.
173173-4. **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`.
174174-5. **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).
175175-6. **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.
176176-7. **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.
177177-8. **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.
178178-9. **Switching presets** — Ask the user first: **overwrite**, **partial**, **merge**, or **skip**?
179179- - **Inspect current preset**: `npx shadcn@latest preset resolve`. Use `--json` when you need structured values.
180180- - **Inspect incoming preset**: `npx shadcn@latest preset decode <code>`. Use `preset url <code>` or `preset open <code>` to share or open the preset builder.
181181- - **Overwrite**: `npx shadcn@latest apply <code>`. Overwrites detected components, fonts, and CSS variables.
182182- - **Partial**: `npx shadcn@latest apply <code> --only theme,font`. Updates only the selected preset parts without reinstalling UI components. Supported values are `theme` and `font`; comma-separated combinations are allowed. `icon` is intentionally not supported, because icon changes may require full component reinstall and transforms.
183183- - **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.
184184- - **Skip**: `npx shadcn@latest init --preset <code> --force --no-reinstall`. Only updates config and CSS, leaves components as-is.
185185- - **Important**: Always run preset commands inside the user's project directory. `apply` only works in an existing project with a `components.json` file. The CLI automatically preserves the current base (`base` vs `radix`) from `components.json`. If you must use a scratch/temp directory (e.g. for `--dry-run` comparisons), pass `--base <current-base>` explicitly — preset codes do not encode the base.
168168+1. Get project context. It is already injected above. Run `npx shadcn@latest info` if you need a refresh.
169169+2. Check installed components first. Before `add`, check the `components` list from context or list `resolvedPaths.ui`. Do not import missing components and do not re-add installed ones.
170170+3. Find components. Use `npx shadcn@latest search`.
171171+4. Get docs and examples. Run `npx shadcn@latest docs <component>`, then fetch the URLs. Use `npx shadcn@latest view` for registry items not yet installed. Use `npx shadcn@latest add --diff` to preview changes on installed components.
172172+5. Install or update. Use `npx shadcn@latest add`. When updating, use `--dry-run` and `--diff` first.
173173+6. Fix imports in third-party components. After adding components from community registries like `@bundui` or `@magicui`, inspect added non-UI files for hardcoded `@/components/ui/...` imports. Rewrite them to match the project's alias from `npx shadcn@latest info`, such as `@workspace/ui/components`.
174174+7. Review added components. After adding a component or block, always read the added files and verify them. Check for missing subcomponents, missing imports, bad composition, or Critical Rule violations. Replace icon imports with the project `iconLibrary` if needed. Fix issues before moving on.
175175+8. Registry must be explicit. If the user asks to add a block or component and does not name a registry, ask which registry to use.
176176+9. Switching presets. Ask first: overwrite, partial, merge, or skip?
177177+ - Inspect current preset: `npx shadcn@latest preset resolve`. Use `--json` for structured values.
178178+ - Inspect incoming preset: `npx shadcn@latest preset decode <code>`. Use `preset url <code>` or `preset open <code>` to share or open the builder.
179179+ - Overwrite: `npx shadcn@latest apply <code>`.
180180+ - Partial: `npx shadcn@latest apply <code> --only theme,font`. Supported values are `theme` and `font`.
181181+ - Merge: `npx shadcn@latest init --preset <code> --force --no-reinstall`, then run `npx shadcn@latest info` and smart merge each installed component with `--dry-run` and `--diff`.
182182+ - Skip: `npx shadcn@latest init --preset <code> --force --no-reinstall`. Updates config and CSS only.
183183+ - Always run preset commands in the user's project directory. `apply` works only in an existing project with `components.json`. The CLI preserves the current base from `components.json`. If using a scratch dir for `--dry-run`, pass `--base <current-base>` explicitly.
186184187185## Updating Components
188186189189-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.**
187187+When updating upstream while keeping local changes, use `--dry-run` and `--diff` for a smart merge. Never fetch raw files from GitHub manually.
190188191191-1. Run `npx shadcn@latest add <component> --dry-run` to see all files that would be affected.
192192-2. For each file, run `npx shadcn@latest add <component> --diff <file>` to see what changed upstream vs local.
193193-3. Decide per file based on the diff:
194194- - No local changes → safe to overwrite.
195195- - Has local changes → read the local file, analyze the diff, and apply upstream updates while preserving local modifications.
196196- - User says "just update everything" → use `--overwrite`, but confirm first.
197197-4. **Never use `--overwrite` without the user's explicit approval.**
189189+1. Run `npx shadcn@latest add <component> --dry-run` to see affected files.
190190+2. For each file, run `npx shadcn@latest add <component> --diff <file>` to compare upstream and local.
191191+3. Decide per file:
192192+ - No local changes: overwrite safely.
193193+ - Has local changes: read the local file, analyze the diff, and apply upstream updates while keeping local changes.
194194+ - User says update everything: use `--overwrite`, but confirm first.
195195+4. Never use `--overwrite` without explicit approval.
198196199197## Quick Reference
200198···241239# Get component docs and example URLs.
242240npx shadcn@latest docs button dialog select
243241244244-# View registry item details (for items not yet installed).
242242+# View registry item details for items not yet installed.
245243npx shadcn@latest view @shadcn/button
246244```
247245248246**Named presets:** `nova`, `vega`, `maia`, `lyra`, `mira`, `luma`
249249-**Templates:** `next`, `vite`, `start`, `react-router`, `astro` (all support `--monorepo`) and `laravel` (not supported for monorepo)
250250-**Preset codes:** Version-prefixed base62 strings (e.g. `a2r6bw` or `b0`), from [ui.shadcn.com](https://ui.shadcn.com).
247247+**Templates:** `next`, `vite`, `start`, `react-router`, `astro` all support `--monorepo`, and `laravel` does not.
248248+**Preset codes:** Version-prefixed base62 strings like `a2r6bw` or `b0`, from [ui.shadcn.com](https://ui.shadcn.com).
251249252250## Detailed References
253251254254-- [rules/forms.md](./rules/forms.md) — FieldGroup, Field, InputGroup, ToggleGroup, FieldSet, validation states
255255-- [rules/composition.md](./rules/composition.md) — Groups, overlays, Card, Tabs, Avatar, Alert, Empty, Toast, Separator, Skeleton, Badge, Button loading
256256-- [rules/icons.md](./rules/icons.md) — data-icon, icon sizing, passing icons as objects
257257-- [rules/styling.md](./rules/styling.md) — Semantic colors, variants, className, spacing, size, truncate, dark mode, cn(), z-index
258258-- [rules/base-vs-radix.md](./rules/base-vs-radix.md) — asChild vs render, Select, ToggleGroup, Slider, Accordion
259259-- [cli.md](./cli.md) — Commands, flags, presets, templates
260260-- [customization.md](./customization.md) — Theming, CSS variables, extending components
252252+- [rules/forms.md](./rules/forms.md) - FieldGroup, Field, InputGroup, ToggleGroup, FieldSet, validation states
253253+- [rules/composition.md](./rules/composition.md) - Groups, overlays, Card, Tabs, Avatar, Alert, Empty, Toast, Separator, Skeleton, Badge, Button loading
254254+- [rules/icons.md](./rules/icons.md) - data-icon, icon sizing, passing icons as objects
255255+- [rules/styling.md](./rules/styling.md) - semantic colors, variants, className, spacing, size, truncate, dark mode, cn(), z-index
256256+- [rules/base-vs-radix.md](./rules/base-vs-radix.md) - asChild vs render, Select, ToggleGroup, Slider, Accordion
257257+- [cli.md](./cli.md) - Commands, flags, presets, templates
258258+- [customization.md](./customization.md) - Theming, CSS variables, extending components
+124-186
skills/shadcn/cli.md
···11# shadcn CLI Reference
2233-Configuration is read from `components.json`.
44-55-> **IMPORTANT:** Always run commands using the project's package runner: `npx shadcn@latest`, `pnpm dlx shadcn@latest`, or `bunx --bun shadcn@latest`. Check `packageManager` from project context to choose the right one. Examples below use `npx shadcn@latest` but substitute the correct runner for the project.
66-77-> **IMPORTANT:** Only use the flags documented below. Do not invent or guess flags — if a flag isn't listed here, it doesn't exist. The CLI auto-detects the package manager from the project's lockfile; there is no `--package-manager` flag.
88-99-## Contents
1010-1111-- Commands: init, apply, add (dry-run, smart merge), search, view, docs, info, build
1212-- Templates: next, vite, start, react-router, astro
1313-- Presets: named, code, URL formats and fields
1414-- Switching presets
33+Configuration comes from `components.json`.
1541616----
55+> **IMPORTANT:** Run commands with the project's package runner: `npx shadcn@latest`, `pnpm dlx shadcn@latest`, or `bunx --bun shadcn@latest`. Use the runner that matches `packageManager`. Examples use `npx shadcn@latest`.
66+> **IMPORTANT:** Only use documented flags. Do not invent flags. The CLI auto-detects package manager from the lockfile, so there is no `--package-manager` flag.
177188## Commands
1992020-### `init` — Initialize or create a project
1010+### `init` - Initialize or create a project
21112212```bash
2313npx shadcn@latest init [components...] [options]
2414```
25152626-Initializes shadcn/ui in an existing project or creates a new project (when `--name` is provided). Optionally installs components in the same step.
1616+Creates or initializes a shadcn/ui project. Can install components at the same time.
27172828-| Flag | Short | Description | Default |
2929-| ----------------------- | ----- | --------------------------------------------------------- | ------- |
3030-| `--template <template>` | `-t` | Template (next, start, vite, next-monorepo, react-router) | — |
3131-| `--preset [name]` | `-p` | Preset configuration (named, code, or URL) | — |
3232-| `--yes` | `-y` | Skip confirmation prompt | `true` |
3333-| `--defaults` | `-d` | Use defaults (`--template=next --preset=base-nova`) | `false` |
3434-| `--force` | `-f` | Force overwrite existing configuration | `false` |
3535-| `--cwd <cwd>` | `-c` | Working directory | current |
3636-| `--name <name>` | `-n` | Name for new project | — |
3737-| `--silent` | `-s` | Mute output | `false` |
3838-| `--rtl` | | Enable RTL support | — |
3939-| `--reinstall` | | Re-install existing UI components | `false` |
4040-| `--monorepo` | | Scaffold a monorepo project | — |
4141-| `--no-monorepo` | | Skip the monorepo prompt | — |
1818+| Flag | Short | Description | Default |
1919+| --- | --- | --- | --- |
2020+| `--template <template>` | `-t` | Template (`next`, `start`, `vite`, `next-monorepo`, `react-router`) | - |
2121+| `--preset [name]` | `-p` | Preset config (`named`, `code`, or `URL`) | - |
2222+| `--yes` | `-y` | Skip prompt | `true` |
2323+| `--defaults` | `-d` | Use defaults (`--template=next --preset=base-nova`) | `false` |
2424+| `--force` | `-f` | Overwrite existing config | `false` |
2525+| `--cwd <cwd>` | `-c` | Working directory | current |
2626+| `--name <name>` | `-n` | New project name | - |
2727+| `--silent` | `-s` | Mute output | `false` |
2828+| `--rtl` | | Enable RTL | - |
2929+| `--reinstall` | | Re-install existing UI components | `false` |
3030+| `--monorepo` | | Scaffold monorepo | - |
3131+| `--no-monorepo` | | Skip monorepo prompt | - |
42324343-`npx shadcn@latest create` is an alias for `npx shadcn@latest init`.
3333+`npx shadcn@latest create` aliases `init`.
44344545-### `apply` — Apply a preset to an existing project
3535+### `apply` - Apply a preset
46364737```bash
4838npx shadcn@latest apply [preset] [options]
4939```
50405151-Applies a preset to an existing project, overwriting preset-driven config, fonts, CSS variables, and detected UI components.
4141+Applies a preset to an existing project and overwrites preset-driven config, fonts, CSS variables, and detected UI components.
52425353-| Flag | Short | Description | Default |
5454-| ------------------- | ----- | ------------------------------------------ | ------- |
5555-| `--preset <preset>` | — | Preset configuration (named, code, or URL) | — |
5656-| `--yes` | `-y` | Skip confirmation prompt | `false` |
5757-| `--cwd <cwd>` | `-c` | Working directory | current |
5858-| `--silent` | `-s` | Mute output | `false` |
4343+| Flag | Short | Description | Default |
4444+| --- | --- | --- | --- |
4545+| `--preset <preset>` | - | Preset config (`named`, `code`, or `URL`) | - |
4646+| `--yes` | `-y` | Skip prompt | `false` |
4747+| `--cwd <cwd>` | `-c` | Working directory | current |
4848+| `--silent` | `-s` | Mute output | `false` |
59496060-`[preset]` is a shorthand for `--preset <preset>`. If both are provided, they must match.
6161-If no preset is provided, the CLI offers to open the custom preset builder on `ui.shadcn.com/create`.
5050+`[preset]` is shorthand for `--preset <preset>`. If both exist, they must match. If no preset is given, the CLI opens the custom preset builder on `ui.shadcn.com/create`.
62516363-### `add` — Add components
5252+### `add` - Add components
64536565-> **IMPORTANT:** To compare local components against upstream or to preview changes, ALWAYS use `npx shadcn@latest add <component> --dry-run`, `--diff`, or `--view`. NEVER fetch raw files from GitHub or other sources manually. The CLI handles registry resolution, file paths, and CSS diffing automatically.
5454+> **IMPORTANT:** To compare local components against upstream or preview changes, always use `npx shadcn@latest add <component> --dry-run`, `--diff`, or `--view`. Never fetch raw files from GitHub or other sources by hand.
66556756```bash
6857npx shadcn@latest add [components...] [options]
6958```
70597171-Accepts component names, registry-prefixed names (`@magicui/shimmer-button`), URLs, or local paths.
6060+Accepts component names, registry names like `@magicui/shimmer-button`, URLs, or local paths.
72617373-| Flag | Short | Description | Default |
7474-| --------------- | ----- | -------------------------------------------------------------------------------------------------------------------- | ------- |
7575-| `--yes` | `-y` | Skip confirmation prompt | `false` |
7676-| `--overwrite` | `-o` | Overwrite existing files | `false` |
7777-| `--cwd <cwd>` | `-c` | Working directory | current |
7878-| `--all` | `-a` | Add all available components | `false` |
7979-| `--path <path>` | `-p` | Target path for the component | — |
8080-| `--silent` | `-s` | Mute output | `false` |
8181-| `--dry-run` | | Preview all changes without writing files | `false` |
8282-| `--diff [path]` | | Show diffs. Without a path, shows the first 5 files. With a path, shows that file only (implies `--dry-run`) | — |
8383-| `--view [path]` | | Show file contents. Without a path, shows the first 5 files. With a path, shows that file only (implies `--dry-run`) | — |
6262+| Flag | Short | Description | Default |
6363+| --- | --- | --- | --- |
6464+| `--yes` | `-y` | Skip prompt | `false` |
6565+| `--overwrite` | `-o` | Overwrite files | `false` |
6666+| `--cwd <cwd>` | `-c` | Working directory | current |
6767+| `--all` | `-a` | Add all components | `false` |
6868+| `--path <path>` | `-p` | Target path | - |
6969+| `--silent` | `-s` | Mute output | `false` |
7070+| `--dry-run` | | Preview changes without writing | `false` |
7171+| `--diff [path]` | | Show diffs. No path shows first 5 files. With path shows only that file. Implies `--dry-run` | - |
7272+| `--view [path]` | | Show file contents. No path shows first 5 files. With path shows only that file. Implies `--dry-run` | - |
84738585-#### Dry-Run Mode
7474+Use `--dry-run` to preview changes. Use `--diff` for local vs upstream diffs. Use `--view` to inspect source without installing. Use `--diff globals.css` for CSS changes. Prefer `add --dry-run/--diff/--view` over `view` when previewing project changes. `view` only shows raw registry metadata.
86758787-Use `--dry-run` to preview what `add` would do without writing any files. `--diff` and `--view` both imply `--dry-run`.
8888-8989-```bash
9090-# Preview all changes.
9191-npx shadcn@latest add button --dry-run
7676+See [Updating Components in SKILL.md](./SKILL.md#updating-components) for smart merge workflow.
92779393-# Show diffs for all files (top 5).
9494-npx shadcn@latest add button --diff
9595-9696-# Show the diff for a specific file.
9797-npx shadcn@latest add button --diff button.tsx
9898-9999-# Show contents for all files (top 5).
100100-npx shadcn@latest add button --view
101101-102102-# Show the full content of a specific file.
103103-npx shadcn@latest add button --view button.tsx
104104-105105-# Works with URLs too.
106106-npx shadcn@latest add https://api.npoint.io/abc123 --dry-run
107107-108108-# CSS diffs.
109109-npx shadcn@latest add button --diff globals.css
110110-```
111111-112112-**When to use dry-run:**
113113-114114-- When the user asks "what files will this add?" or "what will this change?" — use `--dry-run`.
115115-- Before overwriting existing components — use `--diff` to preview the changes first.
116116-- When the user wants to inspect component source code without installing — use `--view`.
117117-- When checking what CSS changes would be made to `globals.css` — use `--diff globals.css`.
118118-- When the user asks to review or audit third-party registry code before installing — use `--view` to inspect the source.
119119-120120-> **`npx shadcn@latest add --dry-run` vs `npx shadcn@latest view`:** Prefer `npx shadcn@latest add --dry-run/--diff/--view` over `npx shadcn@latest view` when the user wants to preview changes to their project. `npx shadcn@latest view` only shows raw registry metadata. `npx shadcn@latest add --dry-run` shows exactly what would happen in the user's project: resolved file paths, diffs against existing files, and CSS updates. Use `npx shadcn@latest view` only when the user wants to browse registry info without a project context.
121121-122122-#### Smart Merge from Upstream
123123-124124-See [Updating Components in SKILL.md](./SKILL.md#updating-components) for the full workflow.
125125-126126-### `search` — Search registries
7878+### `search` - Search registries
1277912880```bash
12981npx shadcn@latest search <registries...> [options]
13082```
13183132132-Fuzzy search across registries. Also aliased as `npx shadcn@latest list`. Without `-q`, lists all items.
8484+Fuzzy search across registries. Aliased as `list`. Without `-q`, lists all items.
13385134134-| Flag | Short | Description | Default |
135135-| ------------------- | ----- | ---------------------- | ------- |
136136-| `--query <query>` | `-q` | Search query | — |
137137-| `--limit <number>` | `-l` | Max items per registry | `100` |
138138-| `--offset <number>` | `-o` | Items to skip | `0` |
139139-| `--cwd <cwd>` | `-c` | Working directory | current |
8686+| Flag | Short | Description | Default |
8787+| --- | --- | --- | --- |
8888+| `--query <query>` | `-q` | Search query | - |
8989+| `--limit <number>` | `-l` | Max items per registry | `100` |
9090+| `--offset <number>` | `-o` | Items to skip | `0` |
9191+| `--cwd <cwd>` | `-c` | Working directory | current |
14092141141-### `view` — View item details
9393+### `view` - View item details
1429414395```bash
14496npx shadcn@latest view <items...> [options]
14597```
14698147147-Displays item info including file contents. Example: `npx shadcn@latest view @shadcn/button`.
9999+Shows item info and file contents. Example: `npx shadcn@latest view @shadcn/button`.
148100149149-### `docs` — Get component documentation URLs
101101+### `docs` - Get documentation URLs
150102151103```bash
152104npx shadcn@latest docs <components...> [options]
153105```
154106155155-Outputs resolved URLs for component documentation, examples, and API references. Accepts one or more component names. Fetch the URLs to get the actual content.
107107+Returns docs, examples, and API URLs. Fetch those URLs for actual content.
156108157157-Example output for `npx shadcn@latest docs input button`:
109109+Example:
158110111111+```bash
112112+npx shadcn@latest docs input button
159113```
160160-base radix
161114162162-input
163163- docs https://ui.shadcn.com/docs/components/radix/input
164164- examples https://raw.githubusercontent.com/.../examples/input-example.tsx
115115+Some components also include an `api` link for the underlying library.
165116166166-button
167167- docs https://ui.shadcn.com/docs/components/radix/button
168168- examples https://raw.githubusercontent.com/.../examples/button-example.tsx
169169-```
170170-171171-Some components include an `api` link to the underlying library (e.g. `cmdk` for the command component).
172172-173173-### `diff` — Check for updates
117117+### `diff` - Check for updates
174118175119Do not use this command. Use `npx shadcn@latest add --diff` instead.
176120177177-### `info` — Project information
121121+### `info` - Project information
178122179123```bash
180124npx shadcn@latest info [options]
181125```
182126183183-Displays project info and `components.json` configuration. Run this first to discover the project's framework, aliases, Tailwind version, and resolved paths.
127127+Shows project info and `components.json`. Run this first to discover framework, aliases, Tailwind version, and resolved paths.
184128185185-| Flag | Short | Description | Default |
186186-| ------------- | ----- | ----------------- | ------- |
187187-| `--cwd <cwd>` | `-c` | Working directory | current |
129129+| Flag | Short | Description | Default |
130130+| --- | --- | --- | --- |
131131+| `--cwd <cwd>` | `-c` | Working directory | current |
188132189189-**Project Info fields:**
133133+`info` fields:
190134191191-| Field | Type | Meaning |
192192-| -------------------- | --------- | ------------------------------------------------------------------ |
193193-| `framework` | `string` | Detected framework (`next`, `vite`, `react-router`, `start`, etc.) |
194194-| `frameworkVersion` | `string` | Framework version (e.g. `15.2.4`) |
195195-| `isSrcDir` | `boolean` | Whether the project uses a `src/` directory |
196196-| `isRSC` | `boolean` | Whether React Server Components are enabled |
197197-| `isTsx` | `boolean` | Whether the project uses TypeScript |
198198-| `tailwindVersion` | `string` | `"v3"` or `"v4"` |
199199-| `tailwindConfigFile` | `string` | Path to the Tailwind config file |
200200-| `tailwindCssFile` | `string` | Path to the global CSS file |
201201-| `aliasPrefix` | `string` | Import alias prefix (e.g. `@`, `~`, `@/`) |
202202-| `packageManager` | `string` | Detected package manager (`npm`, `pnpm`, `yarn`, `bun`) |
135135+| Field | Type | Meaning |
136136+| --- | --- | --- |
137137+| `framework` | `string` | Framework (`next`, `vite`, `react-router`, `start`, etc.) |
138138+| `frameworkVersion` | `string` | Framework version |
139139+| `isSrcDir` | `boolean` | Uses `src/` dir |
140140+| `isRSC` | `boolean` | React Server Components enabled |
141141+| `isTsx` | `boolean` | Uses TypeScript |
142142+| `tailwindVersion` | `string` | `v3` or `v4` |
143143+| `tailwindConfigFile` | `string` | Tailwind config path |
144144+| `tailwindCssFile` | `string` | Global CSS path |
145145+| `aliasPrefix` | `string` | Import alias prefix |
146146+| `packageManager` | `string` | `npm`, `pnpm`, `yarn`, or `bun` |
203147204204-**Components.json fields:**
148148+`components.json` fields:
205149206206-| Field | Type | Meaning |
207207-| -------------------- | --------- | ------------------------------------------------------------------------------------------ |
208208-| `base` | `string` | Primitive library (`radix` or `base`) — determines component APIs and available props |
209209-| `style` | `string` | Visual style (e.g. `nova`, `vega`) |
210210-| `rsc` | `boolean` | RSC flag from config |
211211-| `tsx` | `boolean` | TypeScript flag |
212212-| `tailwind.config` | `string` | Tailwind config path |
213213-| `tailwind.css` | `string` | Global CSS path — this is where custom CSS variables go |
214214-| `iconLibrary` | `string` | Icon library — determines icon import package (e.g. `lucide-react`, `@tabler/icons-react`) |
215215-| `aliases.components` | `string` | Component import alias (e.g. `@/components`) |
216216-| `aliases.utils` | `string` | Utils import alias (e.g. `@/lib/utils`) |
217217-| `aliases.ui` | `string` | UI component alias (e.g. `@/components/ui`) |
218218-| `aliases.lib` | `string` | Lib alias (e.g. `@/lib`) |
219219-| `aliases.hooks` | `string` | Hooks alias (e.g. `@/hooks`) |
220220-| `resolvedPaths` | `object` | Absolute file-system paths for each alias |
221221-| `registries` | `object` | Configured custom registries |
150150+| Field | Type | Meaning |
151151+| --- | --- | --- |
152152+| `base` | `string` | `radix` or `base` |
153153+| `style` | `string` | Visual style |
154154+| `rsc` | `boolean` | RSC flag |
155155+| `tsx` | `boolean` | TypeScript flag |
156156+| `tailwind.config` | `string` | Tailwind config path |
157157+| `tailwind.css` | `string` | Global CSS path |
158158+| `iconLibrary` | `string` | Icon package |
159159+| `aliases.components` | `string` | Components alias |
160160+| `aliases.utils` | `string` | Utils alias |
161161+| `aliases.ui` | `string` | UI alias |
162162+| `aliases.lib` | `string` | Lib alias |
163163+| `aliases.hooks` | `string` | Hooks alias |
164164+| `resolvedPaths` | `object` | Absolute paths |
165165+| `registries` | `object` | Custom registries |
222166223223-**Links fields:**
167167+`info` also includes `Links` with templated URLs. For resolved URLs, use `docs <component>`.
224168225225-The `info` output includes a **Links** section with templated URLs for component docs, source, and examples. For resolved URLs, use `npx shadcn@latest docs <component>` instead.
226226-227227-### `build` — Build a custom registry
169169+### `build` - Build a custom registry
228170229171```bash
230172npx shadcn@latest build [registry] [options]
231173```
232174233233-Builds `registry.json` into individual JSON files for distribution. Default input: `./registry.json`, default output: `./public/r`.
175175+Builds `registry.json` into distributable JSON files. Default input `./registry.json`, default output `./public/r`.
234176235235-| Flag | Short | Description | Default |
236236-| ----------------- | ----- | ----------------- | ------------ |
237237-| `--output <path>` | `-o` | Output directory | `./public/r` |
238238-| `--cwd <cwd>` | `-c` | Working directory | current |
239239-240240----
177177+| Flag | Short | Description | Default |
178178+| --- | --- | --- | --- |
179179+| `--output <path>` | `-o` | Output directory | `./public/r` |
180180+| `--cwd <cwd>` | `-c` | Working directory | current |
241181242182## Templates
243183244244-| Value | Framework | Monorepo support |
245245-| -------------- | -------------- | ---------------- |
246246-| `next` | Next.js | Yes |
247247-| `vite` | Vite | Yes |
248248-| `start` | TanStack Start | Yes |
249249-| `react-router` | React Router | Yes |
250250-| `astro` | Astro | Yes |
251251-| `laravel` | Laravel | No |
184184+| Value | Framework | Monorepo support |
185185+| --- | --- | --- |
186186+| `next` | Next.js | Yes |
187187+| `vite` | Vite | Yes |
188188+| `start` | TanStack Start | Yes |
189189+| `react-router` | React Router | Yes |
190190+| `astro` | Astro | Yes |
191191+| `laravel` | Laravel | No |
252192253253-All templates support monorepo scaffolding via the `--monorepo` flag. When passed, the CLI uses a monorepo-specific template directory (e.g. `next-monorepo`, `vite-monorepo`). When neither `--monorepo` nor `--no-monorepo` is passed, the CLI prompts interactively. Laravel does not support monorepo scaffolding.
254254-255255----
193193+All templates support monorepo scaffolding via `--monorepo`. If neither `--monorepo` nor `--no-monorepo` is passed, the CLI prompts. Laravel does not support monorepo scaffolding.
256194257195## Presets
258196259259-Three ways to specify a preset via `--preset`:
197197+Three preset forms:
260198261261-1. **Named:** `--preset nova` or `--preset lyra`
262262-2. **Code:** `--preset a2r6bw` (version-prefixed base62 string, e.g. `a2r6bw` or `b0`)
263263-3. **URL:** `--preset "https://ui.shadcn.com/init?base=radix&style=nova&..."`
199199+1. Named: `--preset nova` or `--preset lyra`
200200+2. Code: `--preset a2r6bw`
201201+3. URL: `--preset "https://ui.shadcn.com/init?base=radix&style=nova&..."`
264202265265-> **IMPORTANT:** Never try to decode, fetch, or resolve preset codes manually. Preset codes are opaque — pass them directly to `npx shadcn@latest init --preset <code>` and let the CLI handle resolution.
266266-> Use `npx shadcn@latest apply --preset <code>` when overwriting an existing project's preset.
203203+> **IMPORTANT:** Preset codes are opaque. Do not decode, fetch, or resolve them manually. Pass them to `init --preset <code>` and let the CLI handle resolution.
204204+> Use `apply --preset <code>` when overwriting an existing preset.
267205268206## Switching Presets
269207270270-Ask the user first: **overwrite**, **merge**, or **skip** existing components?
208208+Ask first: **overwrite**, **merge**, or **skip** existing components?
271209272272-- **Overwrite / Re-install** → `npx shadcn@latest apply --preset <code>`. Overwrites all detected component files with the new preset styles. Use when the user hasn't customized components.
273273-- **Merge** → `npx shadcn@latest init --preset <code> --force --no-reinstall`, then run `npx shadcn@latest info` to get the list of installed components and use the [smart merge workflow](./SKILL.md#updating-components) to update them one by one, preserving local changes. Use when the user has customized components.
274274-- **Skip** → `npx shadcn@latest init --preset <code> --force --no-reinstall`. Only updates config and CSS variables, leaves existing components as-is.
210210+- **Overwrite / Re-install** → `npx shadcn@latest apply --preset <code>`.
211211+- **Merge** → `npx shadcn@latest init --preset <code> --force --no-reinstall`, then run `npx shadcn@latest info` and smart merge each component one by one.
212212+- **Skip** → `npx shadcn@latest init --preset <code> --force --no-reinstall`.
275213276276-Always run preset commands inside the user's project directory. `apply` only works in an existing project with a `components.json` file. The CLI automatically preserves the current base (`base` vs `radix`) from `components.json`. If you must use a scratch/temp directory (e.g. for `--dry-run` comparisons), pass `--base <current-base>` explicitly — preset codes do not encode the base.
214214+Always run preset commands in the user's project directory. `apply` only works in an existing project with `components.json`. The CLI preserves the current base from `components.json`. If using a scratch dir, pass `--base <current-base>` explicitly because preset codes do not encode base.
+38-124
skills/shadcn/customization.md
···11# Customization & Theming
2233-Components reference semantic CSS variable tokens. Change the variables to change every component.
44-55-## Contents
66-77-- How it works (CSS variables → Tailwind utilities → components)
88-- Color variables and OKLCH format
99-- Dark mode setup
1010-- Changing the theme (presets, CSS variables)
1111-- Adding custom colors (Tailwind v3 and v4)
1212-- Border radius
1313-- Customizing components (variants, className, wrappers)
1414-- Checking for updates
1515-1616----
33+Components use semantic CSS variables. Change variables to change every component.
174185## How It Works
1962020-1. CSS variables defined in `:root` (light) and `.dark` (dark mode).
2121-2. Tailwind maps them to utilities: `bg-primary`, `text-muted-foreground`, etc.
2222-3. Components use these utilities — changing a variable changes all components that reference it.
2323-2424----
77+1. Define CSS vars in `:root` and `.dark`.
88+2. Tailwind maps them to utilities like `bg-primary` and `text-muted-foreground`.
99+3. Components consume those utilities, so one var change updates all consumers.
25102611## Color Variables
27122828-Every color follows the `name` / `name-foreground` convention. The base variable is for backgrounds, `-foreground` is for text/icons on that background.
1313+Use `name` and `name-foreground` pairs. Base var is the background. `-foreground` is text/icons on that background.
29143030-| Variable | Purpose |
3131-| -------------------------------------------- | -------------------------------- |
3232-| `--background` / `--foreground` | Page background and default text |
3333-| `--card` / `--card-foreground` | Card surfaces |
3434-| `--primary` / `--primary-foreground` | Primary buttons and actions |
3535-| `--secondary` / `--secondary-foreground` | Secondary actions |
3636-| `--muted` / `--muted-foreground` | Muted/disabled states |
3737-| `--accent` / `--accent-foreground` | Hover and accent states |
3838-| `--destructive` / `--destructive-foreground` | Error and destructive actions |
3939-| `--border` | Default border color |
4040-| `--input` | Form input borders |
4141-| `--ring` | Focus ring color |
4242-| `--chart-1` through `--chart-5` | Chart/data visualization |
4343-| `--sidebar-*` | Sidebar-specific colors |
4444-| `--surface` / `--surface-foreground` | Secondary surface |
1515+| Variable | Purpose |
1616+| --- | --- |
1717+| `--background` / `--foreground` | Page background and default text |
1818+| `--card` / `--card-foreground` | Card surfaces |
1919+| `--primary` / `--primary-foreground` | Primary actions |
2020+| `--secondary` / `--secondary-foreground` | Secondary actions |
2121+| `--muted` / `--muted-foreground` | Muted and disabled states |
2222+| `--accent` / `--accent-foreground` | Hover and accent states |
2323+| `--destructive` / `--destructive-foreground` | Errors and destructive actions |
2424+| `--border` | Default border color |
2525+| `--input` | Input borders |
2626+| `--ring` | Focus ring |
2727+| `--chart-1` to `--chart-5` | Chart colors |
2828+| `--sidebar-*` | Sidebar colors |
2929+| `--surface` / `--surface-foreground` | Secondary surface |
45304646-Colors use OKLCH: `--primary: oklch(0.205 0 0)` where values are lightness (0–1), chroma (0 = gray), and hue (0–360).
4747-4848----
3131+Colors use OKLCH, for example `--primary: oklch(0.205 0 0)`.
49325033## Dark Mode
51345252-Class-based toggle via `.dark` on the root element. In Next.js, use `next-themes`:
3535+Use class-based dark mode with `.dark` on the root. In Next.js, use `next-themes`:
53365437```tsx
5538import { ThemeProvider } from "next-themes"
···5942</ThemeProvider>
6043```
61446262----
6363-6445## Changing the Theme
65466647```bash
6767-# Apply a preset code from ui.shadcn.com.
6848npx shadcn@latest apply --preset a2r6bw
6969-7070-# Positional shorthand also works.
7149npx shadcn@latest apply a2r6bw
7272-7373-# Switch to a named preset and overwrite existing components.
7450npx shadcn@latest apply --preset nova
7575-7676-# Preserve existing components instead.
7751npx shadcn@latest init --preset nova --force --no-reinstall
7878-7979-# Use a custom theme URL.
8052npx shadcn@latest apply --preset "https://ui.shadcn.com/init?base=radix&style=nova&theme=blue&..."
8153```
82548355Or edit CSS variables directly in `globals.css`.
8484-8585----
86568757## Adding Custom Colors
88588989-Add variables to the file at `tailwindCssFile` from `npx shadcn@latest info` (typically `globals.css`). Never create a new CSS file for this.
5959+Add vars to `tailwindCssFile` from `npx shadcn@latest info`. Do not create a new CSS file.
90609161```css
9292-/* 1. Define in the global CSS file. */
9362:root {
9463 --warning: oklch(0.84 0.16 84);
9564 --warning-foreground: oklch(0.28 0.07 46);
···10069}
10170```
102717272+Tailwind v4:
7373+10374```css
104104-/* 2a. Register with Tailwind v4 (@theme inline). */
10575@theme inline {
10676 --color-warning: var(--warning);
10777 --color-warning-foreground: var(--warning-foreground);
10878}
10979```
11080111111-When `tailwindVersion` is `"v3"` (check via `npx shadcn@latest info`), register in `tailwind.config.js` instead:
8181+Tailwind v3:
1128211383```js
114114-// 2b. Register with Tailwind v3 (tailwind.config.js).
11584module.exports = {
11685 theme: {
11786 extend: {
11887 colors: {
11988 warning: "oklch(var(--warning) / <alpha-value>)",
120120- "warning-foreground":
121121- "oklch(var(--warning-foreground) / <alpha-value>)",
8989+ "warning-foreground": "oklch(var(--warning-foreground) / <alpha-value>)",
12290 },
12391 },
12492 },
12593}
12694```
127959696+Use it in components:
9797+12898```tsx
129129-// 3. Use in components.
13099<div className="bg-warning text-warning-foreground">Warning</div>
131100```
132101133133----
134134-135102## Border Radius
136103137137-`--radius` controls border radius globally. Components derive values from it (`rounded-lg` = `var(--radius)`, `rounded-md` = `calc(var(--radius) - 2px)`).
138138-139139----
104104+`--radius` controls border radius globally. `rounded-lg` and `rounded-md` derive from it.
140105141106## Customizing Components
142107143143-See also: [rules/styling.md](./rules/styling.md) for Incorrect/Correct examples.
144144-145145-Prefer these approaches in order:
146146-147147-### 1. Built-in variants
148148-149149-```tsx
150150-<Button variant="outline" size="sm">
151151- Click
152152-</Button>
153153-```
154154-155155-### 2. Tailwind classes via `className`
156156-157157-```tsx
158158-<Card className="mx-auto max-w-md">...</Card>
159159-```
160160-161161-### 3. Add a new variant
162162-163163-Edit the component source to add a variant via `cva`:
164164-165165-```tsx
166166-// components/ui/button.tsx
167167-warning: "bg-warning text-warning-foreground hover:bg-warning/90",
168168-```
169169-170170-### 4. Wrapper components
171171-172172-Compose shadcn/ui primitives into higher-level components:
173173-174174-```tsx
175175-export function ConfirmDialog({ title, description, onConfirm, children }) {
176176- return (
177177- <AlertDialog>
178178- <AlertDialogTrigger asChild>{children}</AlertDialogTrigger>
179179- <AlertDialogContent>
180180- <AlertDialogHeader>
181181- <AlertDialogTitle>{title}</AlertDialogTitle>
182182- <AlertDialogDescription>{description}</AlertDialogDescription>
183183- </AlertDialogHeader>
184184- <AlertDialogFooter>
185185- <AlertDialogCancel>Cancel</AlertDialogCancel>
186186- <AlertDialogAction onClick={onConfirm}>Confirm</AlertDialogAction>
187187- </AlertDialogFooter>
188188- </AlertDialogContent>
189189- </AlertDialog>
190190- )
191191-}
192192-```
193193-194194----
108108+1. Built-in variants.
109109+2. `className` for layout.
110110+3. Add a new variant in the component source.
111111+4. Wrapper components for higher-level composition.
195112196113## Checking for Updates
197114198115```bash
199116npx shadcn@latest add button --diff
117117+npx shadcn@latest add button --dry-run
118118+npx shadcn@latest add button --diff button.tsx
200119```
201120202202-To preview exactly what would change before updating, use `--dry-run` and `--diff`:
203203-204204-```bash
205205-npx shadcn@latest add button --dry-run # see all affected files
206206-npx shadcn@latest add button --diff button.tsx # see the diff for a specific file
207207-```
121121+Use `--dry-run` and `--diff` before updating.
208122209209-See [Updating Components in SKILL.md](./SKILL.md#updating-components) for the full smart merge workflow.
123123+See [Updating Components in SKILL.md](./SKILL.md#updating-components).
+16-56
skills/shadcn/mcp.md
···11# shadcn MCP Server
2233-The CLI includes an MCP server that lets AI assistants search, browse, view, and install components from registries.
44-55----
33+The CLI includes an MCP server for registry search, browsing, and install flows.
6475## Setup
8697```bash
1010-shadcn mcp # start the MCP server (stdio)
1111-shadcn mcp init # write config for your editor
88+shadcn mcp
99+shadcn mcp init
1210```
13111414-Editor config files:
1212+Editor configs:
15131614| Editor | Config file |
1717-|--------|------------|
1515+| --- | --- |
1816| Claude Code | `.mcp.json` |
1917| Cursor | `.cursor/mcp.json` |
2018| VS Code | `.vscode/mcp.json` |
2119| OpenCode | `opencode.json` |
2222-| Codex | `~/.codex/config.toml` (manual) |
2323-2424----
2020+| Codex | `~/.codex/config.toml` |
25212622## Tools
27232828-> **Tip:** MCP tools handle registry operations (search, view, install). For project configuration (aliases, framework, Tailwind version), use `npx shadcn@latest info` — there is no MCP equivalent.
2929-3030-### `shadcn:get_project_registries`
3131-3232-Returns registry names from `components.json`. Errors if no `components.json` exists.
3333-3434-**Input:** none
3535-3636-### `shadcn:list_items_in_registries`
3737-3838-Lists all items from one or more registries.
3939-4040-**Input:** `registries` (string[]), `limit` (number, optional), `offset` (number, optional)
4141-4242-### `shadcn:search_items_in_registries`
4343-4444-Fuzzy search across registries.
4545-4646-**Input:** `registries` (string[]), `query` (string), `limit` (number, optional), `offset` (number, optional)
4747-4848-### `shadcn:view_items_in_registries`
4949-5050-View item details including full file contents.
5151-5252-**Input:** `items` (string[]) — e.g. `["@shadcn/button", "@shadcn/card"]`
5353-5454-### `shadcn:get_item_examples_from_registries`
5555-5656-Find usage examples and demos with source code.
5757-5858-**Input:** `registries` (string[]), `query` (string) — e.g. `"accordion-demo"`, `"button example"`
5959-6060-### `shadcn:get_add_command_for_items`
6161-6262-Returns the CLI install command.
6363-6464-**Input:** `items` (string[]) — e.g. `["@shadcn/button"]`
6565-6666-### `shadcn:get_audit_checklist`
6767-6868-Returns a checklist for verifying components (imports, deps, lint, TypeScript).
6969-7070-**Input:** none
2424+> **Tip:** MCP tools handle registry operations. For project config like aliases, framework, and Tailwind version, use `npx shadcn@latest info`.
71257272----
2626+- `shadcn:get_project_registries` - registry names from `components.json`
2727+- `shadcn:list_items_in_registries` - list items in registries
2828+- `shadcn:search_items_in_registries` - fuzzy search
2929+- `shadcn:view_items_in_registries` - view item details and file contents
3030+- `shadcn:get_item_examples_from_registries` - usage examples and demos
3131+- `shadcn:get_add_command_for_items` - install command
3232+- `shadcn:get_audit_checklist` - import, dependency, lint, TypeScript checklist
73337434## Configuring Registries
75357676-Registries are set in `components.json`. The `@shadcn` registry is always built-in.
3636+Registries live in `components.json`. `@shadcn` is built in.
77377838```json
7939{
···89499050- Names must start with `@`.
9151- URLs must contain `{name}`.
9292-- `${VAR}` references are resolved from environment variables.
5252+- `${VAR}` comes from environment variables.
93539454Community registry index: `https://ui.shadcn.com/r/registries.json`
+11-250
skills/shadcn/rules/base-vs-radix.md
···11# Base vs Radix
2233-API differences between `base` and `radix`. Check the `base` field from `npx shadcn@latest info`.
33+Check `base` in `npx shadcn@latest info`.
4455-## Contents
55+## Key Differences
6677-- Composition: asChild vs render
88-- Button / trigger as non-button element
99-- Select (items prop, placeholder, positioning, multiple, object values)
1010-- ToggleGroup (type vs multiple)
1111-- Slider (scalar vs array)
1212-- Accordion (type and defaultValue)
77+- Radix uses `asChild`. Base uses `render`.
88+- Base needs `nativeButton={false}` when `render` changes a button to a non-button element.
99+- Select differs by `items`, placeholder handling, positioning, and object values.
1010+- ToggleGroup differs by `type` vs `multiple` and by `defaultValue` shape.
1111+- Slider uses a number for single thumb in base. Radix uses an array.
1212+- Accordion uses `multiple` in base. Radix uses `type="single"` or `type="multiple"`.
13131414----
1515-1616-## Composition: asChild (radix) vs render (base)
1717-1818-Radix uses `asChild` to replace the default element. Base uses `render`. Don't wrap triggers in extra elements.
1919-2020-**Incorrect:**
2121-2222-```tsx
2323-<DialogTrigger>
2424- <div>
2525- <Button>Open</Button>
2626- </div>
2727-</DialogTrigger>
2828-```
2929-3030-**Correct (radix):**
1414+## Examples
31153216```tsx
3317<DialogTrigger asChild>
3418 <Button>Open</Button>
3519</DialogTrigger>
3636-```
37203838-**Correct (base):**
3939-4040-```tsx
4121<DialogTrigger render={<Button />}>Open</DialogTrigger>
4222```
43234444-This applies to all trigger and close components: `DialogTrigger`, `SheetTrigger`, `AlertDialogTrigger`, `DropdownMenuTrigger`, `PopoverTrigger`, `TooltipTrigger`, `CollapsibleTrigger`, `DialogClose`, `SheetClose`, `NavigationMenuLink`, `BreadcrumbLink`, `SidebarMenuButton`, `Badge`, `Item`.
4545-4646----
4747-4848-## Button / trigger as non-button element (base only)
4949-5050-When `render` changes an element to a non-button (`<a>`, `<span>`), add `nativeButton={false}`.
5151-5252-**Incorrect (base):** missing `nativeButton={false}`.
5353-5454-```tsx
5555-<Button render={<a href="/docs" />}>Read the docs</Button>
5656-```
5757-5858-**Correct (base):**
5959-6024```tsx
6125<Button render={<a href="/docs" />} nativeButton={false}>
6226 Read the docs
6327</Button>
6464-```
65286666-**Correct (radix):**
6767-6868-```tsx
6929<Button asChild>
7030 <a href="/docs">Read the docs</a>
7131</Button>
7232```
73337474-Same for triggers whose `render` is not a `Button`:
7575-7634```tsx
7777-// base.
7878-<PopoverTrigger render={<InputGroupAddon />} nativeButton={false}>
7979- Pick date
8080-</PopoverTrigger>
8181-```
8282-8383----
8484-8585-## Select
8686-8787-**items prop (base only).** Base requires an `items` prop on the root. Radix uses inline JSX only.
8888-8989-**Incorrect (base):**
9090-9191-```tsx
9292-<Select>
9393- <SelectTrigger><SelectValue placeholder="Select a fruit" /></SelectTrigger>
9494-</Select>
9595-```
9696-9797-**Correct (base):**
9898-9999-```tsx
100100-const items = [
101101- { label: "Select a fruit", value: null },
102102- { label: "Apple", value: "apple" },
103103- { label: "Banana", value: "banana" },
104104-]
105105-10635<Select items={items}>
107107- <SelectTrigger>
108108- <SelectValue />
109109- </SelectTrigger>
110110- <SelectContent>
111111- <SelectGroup>
112112- {items.map((item) => (
113113- <SelectItem key={item.value} value={item.value}>{item.label}</SelectItem>
114114- ))}
115115- </SelectGroup>
116116- </SelectContent>
3636+ <SelectTrigger><SelectValue /></SelectTrigger>
11737</Select>
118118-```
119119-120120-**Correct (radix):**
12138122122-```tsx
12339<Select>
124124- <SelectTrigger>
125125- <SelectValue placeholder="Select a fruit" />
126126- </SelectTrigger>
127127- <SelectContent>
128128- <SelectGroup>
129129- <SelectItem value="apple">Apple</SelectItem>
130130- <SelectItem value="banana">Banana</SelectItem>
131131- </SelectGroup>
132132- </SelectContent>
4040+ <SelectTrigger><SelectValue placeholder="Select a fruit" /></SelectTrigger>
13341</Select>
13442```
13543136136-**Placeholder.** Base uses a `{ value: null }` item in the items array. Radix uses `<SelectValue placeholder="...">`.
137137-138138-**Content positioning.** Base uses `alignItemWithTrigger`. Radix uses `position`.
139139-14044```tsx
141141-// base.
142142-<SelectContent alignItemWithTrigger={false} side="bottom">
143143-144144-// radix.
145145-<SelectContent position="popper">
146146-```
147147-148148----
149149-150150-## Select — multiple selection and object values (base only)
151151-152152-Base supports `multiple`, render-function children on `SelectValue`, and object values with `itemToStringValue`. Radix is single-select with string values only.
153153-154154-**Correct (base — multiple selection):**
155155-156156-```tsx
157157-<Select items={items} multiple defaultValue={[]}>
158158- <SelectTrigger>
159159- <SelectValue>
160160- {(value: string[]) => value.length === 0 ? "Select fruits" : `${value.length} selected`}
161161- </SelectValue>
162162- </SelectTrigger>
163163- ...
164164-</Select>
165165-```
166166-167167-**Correct (base — object values):**
168168-169169-```tsx
170170-<Select defaultValue={plans[0]} itemToStringValue={(plan) => plan.name}>
171171- <SelectTrigger>
172172- <SelectValue>{(value) => value.name}</SelectValue>
173173- </SelectTrigger>
174174- ...
175175-</Select>
176176-```
177177-178178----
179179-180180-## ToggleGroup
181181-182182-Base uses a `multiple` boolean prop. Radix uses `type="single"` or `type="multiple"`.
183183-184184-**Incorrect (base):**
185185-186186-```tsx
187187-<ToggleGroup type="single" defaultValue="daily">
188188- <ToggleGroupItem value="daily">Daily</ToggleGroupItem>
189189-</ToggleGroup>
190190-```
191191-192192-**Correct (base):**
193193-194194-```tsx
195195-// Single (no prop needed), defaultValue is always an array.
19645<ToggleGroup defaultValue={["daily"]} spacing={2}>
19746 <ToggleGroupItem value="daily">Daily</ToggleGroupItem>
198198- <ToggleGroupItem value="weekly">Weekly</ToggleGroupItem>
19947</ToggleGroup>
20048201201-// Multi-selection.
202202-<ToggleGroup multiple>
203203- <ToggleGroupItem value="bold">Bold</ToggleGroupItem>
204204- <ToggleGroupItem value="italic">Italic</ToggleGroupItem>
205205-</ToggleGroup>
206206-```
207207-208208-**Correct (radix):**
209209-210210-```tsx
211211-// Single, defaultValue is a string.
21249<ToggleGroup type="single" defaultValue="daily" spacing={2}>
21350 <ToggleGroupItem value="daily">Daily</ToggleGroupItem>
214214- <ToggleGroupItem value="weekly">Weekly</ToggleGroupItem>
215215-</ToggleGroup>
216216-217217-// Multi-selection.
218218-<ToggleGroup type="multiple">
219219- <ToggleGroupItem value="bold">Bold</ToggleGroupItem>
220220- <ToggleGroupItem value="italic">Italic</ToggleGroupItem>
22151</ToggleGroup>
22252```
22353224224-**Controlled single value:**
225225-226226-```tsx
227227-// base — wrap/unwrap arrays.
228228-const [value, setValue] = React.useState("normal")
229229-<ToggleGroup value={[value]} onValueChange={(v) => setValue(v[0])}>
230230-231231-// radix — plain string.
232232-const [value, setValue] = React.useState("normal")
233233-<ToggleGroup type="single" value={value} onValueChange={setValue}>
234234-```
235235-236236----
237237-238238-## Slider
239239-240240-Base accepts a plain number for a single thumb. Radix always requires an array.
241241-242242-**Incorrect (base):**
243243-244244-```tsx
245245-<Slider defaultValue={[50]} max={100} step={1} />
246246-```
247247-248248-**Correct (base):**
249249-25054```tsx
25155<Slider defaultValue={50} max={100} step={1} />
252252-```
253253-254254-**Correct (radix):**
255255-256256-```tsx
25756<Slider defaultValue={[50]} max={100} step={1} />
25857```
259259-260260-Both use arrays for range sliders. Controlled `onValueChange` in base may need a cast:
261261-262262-```tsx
263263-// base.
264264-const [value, setValue] = React.useState([0.3, 0.7])
265265-<Slider value={value} onValueChange={(v) => setValue(v as number[])} />
266266-267267-// radix.
268268-const [value, setValue] = React.useState([0.3, 0.7])
269269-<Slider value={value} onValueChange={setValue} />
270270-```
271271-272272----
273273-274274-## Accordion
275275-276276-Radix requires `type="single"` or `type="multiple"` and supports `collapsible`. `defaultValue` is a string. Base uses no `type` prop, uses `multiple` boolean, and `defaultValue` is always an array.
277277-278278-**Incorrect (base):**
279279-280280-```tsx
281281-<Accordion type="single" collapsible defaultValue="item-1">
282282- <AccordionItem value="item-1">...</AccordionItem>
283283-</Accordion>
284284-```
285285-286286-**Correct (base):**
2875828859```tsx
28960<Accordion defaultValue={["item-1"]}>
29061 <AccordionItem value="item-1">...</AccordionItem>
29162</Accordion>
29263293293-// Multi-select.
294294-<Accordion multiple defaultValue={["item-1", "item-2"]}>
295295- <AccordionItem value="item-1">...</AccordionItem>
296296- <AccordionItem value="item-2">...</AccordionItem>
297297-</Accordion>
298298-```
299299-300300-**Correct (radix):**
301301-302302-```tsx
30364<Accordion type="single" collapsible defaultValue="item-1">
30465 <AccordionItem value="item-1">...</AccordionItem>
30566</Accordion>
+17-125
skills/shadcn/rules/composition.md
···11# Component Composition
2233-## Contents
44-55-- Items always inside their Group component
66-- Callouts use Alert
77-- Empty states use Empty component
88-- Toast notifications use sonner
99-- Choosing between overlay components
1010-- Dialog, Sheet, and Drawer always need a Title
1111-- Card structure
1212-- Button has no isPending or isLoading prop
1313-- TabsTrigger must be inside TabsList
1414-- Avatar always needs AvatarFallback
1515-- Use Separator instead of raw hr or border divs
1616-- Use Skeleton for loading placeholders
1717-- Use Badge instead of custom styled spans
1818-1919----
2020-2121-## Items always inside their Group component
33+## Rules
2242323-Never render items directly inside the content container.
55+- Items stay inside their group component.
66+- Use `Alert` for callouts.
77+- Use `Empty` for empty states.
88+- Use `sonner` for toasts.
99+- Use `Dialog`, `Sheet`, `Drawer`, `HoverCard`, or `Popover` by intent.
1010+- `Dialog`, `Sheet`, and `Drawer` always need a title.
1111+- Use full `Card` composition.
1212+- `Button` has no `isPending` or `isLoading` prop.
1313+- `TabsTrigger` must stay inside `TabsList`.
1414+- `Avatar` needs `AvatarFallback`.
1515+- Use `Separator` instead of raw `<hr>` or border divs.
1616+- Use `Skeleton` for loading placeholders.
1717+- Use `Badge` instead of custom spans.
24182525-**Incorrect:**
2626-2727-```tsx
2828-<SelectContent>
2929- <SelectItem value="apple">Apple</SelectItem>
3030- <SelectItem value="banana">Banana</SelectItem>
3131-</SelectContent>
3232-```
3333-3434-**Correct:**
1919+## Examples
35203621```tsx
3722<SelectContent>
···4227</SelectContent>
4328```
44294545-This applies to all group-based components:
4646-4747-| Item | Group |
4848-|------|-------|
4949-| `SelectItem`, `SelectLabel` | `SelectGroup` |
5050-| `DropdownMenuItem`, `DropdownMenuLabel`, `DropdownMenuSub` | `DropdownMenuGroup` |
5151-| `MenubarItem` | `MenubarGroup` |
5252-| `ContextMenuItem` | `ContextMenuGroup` |
5353-| `CommandItem` | `CommandGroup` |
5454-5555----
5656-5757-## Callouts use Alert
5858-5930```tsx
6031<Alert>
6132 <AlertTitle>Warning</AlertTitle>
6233 <AlertDescription>Something needs attention.</AlertDescription>
6334</Alert>
6435```
6565-6666----
6767-6868-## Empty states use Empty component
69367037```tsx
7138<Empty>
···7441 <EmptyTitle>No projects yet</EmptyTitle>
7542 <EmptyDescription>Get started by creating a new project.</EmptyDescription>
7643 </EmptyHeader>
7777- <EmptyContent>
7878- <Button>Create Project</Button>
7979- </EmptyContent>
4444+ <EmptyContent><Button>Create Project</Button></EmptyContent>
8045</Empty>
8146```
8282-8383----
8484-8585-## Toast notifications use sonner
86478748```tsx
8849import { toast } from "sonner"
89509051toast.success("Changes saved.")
9152toast.error("Something went wrong.")
9292-toast("File deleted.", {
9393- action: { label: "Undo", onClick: () => undoDelete() },
9494-})
9553```
96549797----
9898-9999-## Choosing between overlay components
100100-101101-| Use case | Component |
102102-|----------|-----------|
103103-| Focused task that requires input | `Dialog` |
104104-| Destructive action confirmation | `AlertDialog` |
105105-| Side panel with details or filters | `Sheet` |
106106-| Mobile-first bottom panel | `Drawer` |
107107-| Quick info on hover | `HoverCard` |
108108-| Small contextual content on click | `Popover` |
109109-110110----
111111-112112-## Dialog, Sheet, and Drawer always need a Title
113113-114114-`DialogTitle`, `SheetTitle`, `DrawerTitle` are required for accessibility. Use `className="sr-only"` if visually hidden.
115115-116116-```tsx
117117-<DialogContent>
118118- <DialogHeader>
119119- <DialogTitle>Edit Profile</DialogTitle>
120120- <DialogDescription>Update your profile.</DialogDescription>
121121- </DialogHeader>
122122- ...
123123-</DialogContent>
124124-```
125125-126126----
127127-128128-## Card structure
129129-130130-Use full composition — don't dump everything into `CardContent`:
131131-13255```tsx
13356<Card>
13457 <CardHeader>
···13659 <CardDescription>Manage your team.</CardDescription>
13760 </CardHeader>
13861 <CardContent>...</CardContent>
139139- <CardFooter>
140140- <Button>Invite</Button>
141141- </CardFooter>
6262+ <CardFooter><Button>Invite</Button></CardFooter>
14263</Card>
14364```
14465145145----
146146-147147-## Button has no isPending or isLoading prop
148148-149149-Compose with `Spinner` + `data-icon` + `disabled`:
150150-15166```tsx
15267<Button disabled>
15368 <Spinner data-icon="inline-start" />
15469 Saving...
15570</Button>
15671```
157157-158158----
159159-160160-## TabsTrigger must be inside TabsList
161161-162162-Never render `TabsTrigger` directly inside `Tabs` — always wrap in `TabsList`:
1637216473```tsx
16574<Tabs defaultValue="account">
16675 <TabsList>
16776 <TabsTrigger value="account">Account</TabsTrigger>
168168- <TabsTrigger value="password">Password</TabsTrigger>
16977 </TabsList>
17078 <TabsContent value="account">...</TabsContent>
17179</Tabs>
17280```
17381174174----
175175-176176-## Avatar always needs AvatarFallback
177177-178178-Always include `AvatarFallback` for when the image fails to load:
179179-18082```tsx
18183<Avatar>
18284 <AvatarImage src="/avatar.png" alt="User" />
18385 <AvatarFallback>JD</AvatarFallback>
18486</Avatar>
18587```
186186-187187----
188188-189189-## Use existing components instead of custom markup
190190-191191-| Instead of | Use |
192192-|---|---|
193193-| `<hr>` or `<div className="border-t">` | `<Separator />` |
194194-| `<div className="animate-pulse">` with styled divs | `<Skeleton className="h-4 w-3/4" />` |
195195-| `<span className="rounded-full bg-green-100 ...">` | `<Badge variant="secondary">` |
+15-134
skills/shadcn/rules/forms.md
···11# Forms & Inputs
2233-## Contents
33+## Rules
4455-- Forms use FieldGroup + Field
66-- InputGroup requires InputGroupInput/InputGroupTextarea
77-- Buttons inside inputs use InputGroup + InputGroupAddon
88-- Option sets (2–7 choices) use ToggleGroup
99-- FieldSet + FieldLegend for grouping related fields
1010-- Field validation and disabled states
55+- Use `FieldGroup` + `Field` for forms.
66+- Use `InputGroupInput` and `InputGroupTextarea` inside `InputGroup`.
77+- Use `InputGroup` + `InputGroupAddon` for buttons inside inputs.
88+- Use `ToggleGroup` for 2 to 7 options.
99+- Use `FieldSet` + `FieldLegend` for grouped checkboxes or radios.
1010+- Use `data-invalid` and `data-disabled` on the field. Use `aria-invalid` or `disabled` on the control.
11111212----
1313-1414-## Forms use FieldGroup + Field
1515-1616-Always use `FieldGroup` + `Field` — never raw `div` with `space-y-*`:
1212+## Examples
17131814```tsx
1915<FieldGroup>
2016 <Field>
2117 <FieldLabel htmlFor="email">Email</FieldLabel>
2218 <Input id="email" type="email" />
2323- </Field>
2424- <Field>
2525- <FieldLabel htmlFor="password">Password</FieldLabel>
2626- <Input id="password" type="password" />
2719 </Field>
2820</FieldGroup>
2921```
30223131-Use `Field orientation="horizontal"` for settings pages. Use `FieldLabel className="sr-only"` for visually hidden labels.
3232-3333-**Choosing form controls:**
3434-3535-- Simple text input → `Input`
3636-- Dropdown with predefined options → `Select`
3737-- Searchable dropdown → `Combobox`
3838-- Native HTML select (no JS) → `native-select`
3939-- Boolean toggle → `Switch` (for settings) or `Checkbox` (for forms)
4040-- Single choice from few options → `RadioGroup`
4141-- Toggle between 2–5 options → `ToggleGroup` + `ToggleGroupItem`
4242-- OTP/verification code → `InputOTP`
4343-- Multi-line text → `Textarea`
4444-4545----
4646-4747-## InputGroup requires InputGroupInput/InputGroupTextarea
4848-4949-Never use raw `Input` or `Textarea` inside an `InputGroup`.
5050-5151-**Incorrect:**
5252-5323```tsx
5454-<InputGroup>
5555- <Input placeholder="Search..." />
5656-</InputGroup>
2424+<Field orientation="horizontal">
2525+ <FieldLabel className="sr-only">Search</FieldLabel>
2626+ <InputGroup>
2727+ <InputGroupInput placeholder="Search..." />
2828+ </InputGroup>
2929+</Field>
5730```
5858-5959-**Correct:**
60316132```tsx
6262-import { InputGroup, InputGroupInput } from "@/components/ui/input-group"
6363-6464-<InputGroup>
6565- <InputGroupInput placeholder="Search..." />
6666-</InputGroup>
6767-```
6868-6969----
7070-7171-## Buttons inside inputs use InputGroup + InputGroupAddon
7272-7373-Never place a `Button` directly inside or adjacent to an `Input` with custom positioning.
7474-7575-**Incorrect:**
7676-7777-```tsx
7878-<div className="relative">
7979- <Input placeholder="Search..." className="pr-10" />
8080- <Button className="absolute right-0 top-0" size="icon">
8181- <SearchIcon />
8282- </Button>
8383-</div>
8484-```
8585-8686-**Correct:**
8787-8888-```tsx
8989-import { InputGroup, InputGroupInput, InputGroupAddon } from "@/components/ui/input-group"
9090-9133<InputGroup>
9234 <InputGroupInput placeholder="Search..." />
9335 <InputGroupAddon>
···9739 </InputGroupAddon>
9840</InputGroup>
9941```
100100-101101----
102102-103103-## Option sets (2–7 choices) use ToggleGroup
104104-105105-Don't manually loop `Button` components with active state.
106106-107107-**Incorrect:**
108108-109109-```tsx
110110-const [selected, setSelected] = useState("daily")
111111-112112-<div className="flex gap-2">
113113- {["daily", "weekly", "monthly"].map((option) => (
114114- <Button
115115- key={option}
116116- variant={selected === option ? "default" : "outline"}
117117- onClick={() => setSelected(option)}
118118- >
119119- {option}
120120- </Button>
121121- ))}
122122-</div>
123123-```
124124-125125-**Correct:**
1264212743```tsx
128128-import { ToggleGroup, ToggleGroupItem } from "@/components/ui/toggle-group"
129129-130130-<ToggleGroup spacing={2}>
4444+<ToggleGroup defaultValue={["daily"]} spacing={2}>
13145 <ToggleGroupItem value="daily">Daily</ToggleGroupItem>
13246 <ToggleGroupItem value="weekly">Weekly</ToggleGroupItem>
133133- <ToggleGroupItem value="monthly">Monthly</ToggleGroupItem>
13447</ToggleGroup>
13548```
13649137137-Combine with `Field` for labelled toggle groups:
138138-139139-```tsx
140140-<Field orientation="horizontal">
141141- <FieldTitle id="theme-label">Theme</FieldTitle>
142142- <ToggleGroup aria-labelledby="theme-label" spacing={2}>
143143- <ToggleGroupItem value="light">Light</ToggleGroupItem>
144144- <ToggleGroupItem value="dark">Dark</ToggleGroupItem>
145145- <ToggleGroupItem value="system">System</ToggleGroupItem>
146146- </ToggleGroup>
147147-</Field>
148148-```
149149-150150-> **Note:** `defaultValue` and `type`/`multiple` props differ between base and radix. See [base-vs-radix.md](./base-vs-radix.md#togglegroup).
151151-152152----
153153-154154-## FieldSet + FieldLegend for grouping related fields
155155-156156-Use `FieldSet` + `FieldLegend` for related checkboxes, radios, or switches — not `div` with a heading:
157157-15850```tsx
15951<FieldSet>
16052 <FieldLegend variant="label">Preferences</FieldLegend>
161161- <FieldDescription>Select all that apply.</FieldDescription>
16253 <FieldGroup className="gap-3">
16354 <Field orientation="horizontal">
16455 <Checkbox id="dark" />
···16859</FieldSet>
16960```
17061171171----
172172-173173-## Field validation and disabled states
174174-175175-Both attributes are needed — `data-invalid`/`data-disabled` styles the field (label, description), while `aria-invalid`/`disabled` styles the control.
176176-17762```tsx
178178-// Invalid.
17963<Field data-invalid>
18064 <FieldLabel htmlFor="email">Email</FieldLabel>
18165 <Input id="email" aria-invalid />
18266 <FieldDescription>Invalid email address.</FieldDescription>
18367</Field>
18468185185-// Disabled.
18669<Field data-disabled>
18770 <FieldLabel htmlFor="email">Email</FieldLabel>
18871 <Input id="email" disabled />
18972</Field>
19073```
191191-192192-Works for all controls: `Input`, `Textarea`, `Select`, `Checkbox`, `RadioGroupItem`, `Switch`, `Slider`, `NativeSelect`, `InputOTP`.
+8-64
skills/shadcn/rules/icons.md
···11# Icons
2233-**Always use the project's configured `iconLibrary` for imports.** Check the `iconLibrary` field from project context: `lucide` → `lucide-react`, `tabler` → `@tabler/icons-react`, etc. Never assume `lucide-react`.
33+Use the project's configured `iconLibrary` for imports. Do not assume `lucide-react`.
4455----
66-77-## Icons in Button use data-icon attribute
88-99-Add `data-icon="inline-start"` (prefix) or `data-icon="inline-end"` (suffix) to the icon. No sizing classes on the icon.
1010-1111-**Incorrect:**
55+## Rules
1261313-```tsx
1414-<Button>
1515- <SearchIcon className="mr-2 size-4" />
1616- Search
1717-</Button>
1818-```
77+- Icons in `Button` use `data-icon="inline-start"` or `data-icon="inline-end"`.
88+- Do not size icons inside shadcn components unless the user asks for custom sizes.
99+- Pass icons as component objects, not string keys.
19102020-**Correct:**
1111+## Examples
21122213```tsx
2314<Button>
2424- <SearchIcon data-icon="inline-start"/>
1515+ <SearchIcon data-icon="inline-start" />
2516 Search
2617</Button>
27182819<Button>
2920 Next
3030- <ArrowRightIcon data-icon="inline-end"/>
3131-</Button>
3232-```
3333-3434----
3535-3636-## No sizing classes on icons inside components
3737-3838-Components handle icon sizing via CSS. Don't add `size-4`, `w-4 h-4`, or other sizing classes to icons inside `Button`, `DropdownMenuItem`, `Alert`, `Sidebar*`, or other shadcn components. Unless the user explicitly asks for custom icon sizes.
3939-4040-**Incorrect:**
4141-4242-```tsx
4343-<Button>
4444- <SearchIcon className="size-4" data-icon="inline-start" />
4545- Search
2121+ <ArrowRightIcon data-icon="inline-end" />
4622</Button>
4747-4848-<DropdownMenuItem>
4949- <SettingsIcon className="mr-2 size-4" />
5050- Settings
5151-</DropdownMenuItem>
5223```
53245454-**Correct:**
5555-5625```tsx
5726<Button>
5827 <SearchIcon data-icon="inline-start" />
···6534</DropdownMenuItem>
6635```
67366868----
6969-7070-## Pass icons as component objects, not string keys
7171-7272-Use `icon={CheckIcon}`, not a string key to a lookup map.
7373-7474-**Incorrect:**
7575-7637```tsx
7777-const iconMap = {
7878- check: CheckIcon,
7979- alert: AlertIcon,
8080-}
8181-8282-function StatusBadge({ icon }: { icon: string }) {
8383- const Icon = iconMap[icon]
8484- return <Icon />
8585-}
8686-8787-<StatusBadge icon="check" />
8888-```
8989-9090-**Correct:**
9191-9292-```tsx
9393-// Import from the project's configured iconLibrary (e.g. lucide-react, @tabler/icons-react).
9438import { CheckIcon } from "lucide-react"
95399640function StatusBadge({ icon: Icon }: { icon: React.ComponentType }) {
+15-122
skills/shadcn/rules/styling.md
···11# Styling & Customization
2233-See [customization.md](../customization.md) for theming, CSS variables, and adding custom colors.
33+See [customization.md](../customization.md) for theming, CSS variables, and custom colors.
4455-## Contents
55+## Core Rules
6677-- Semantic colors
88-- Built-in variants first
99-- className for layout only
1010-- No space-x-* / space-y-*
1111-- Prefer size-* over w-* h-* when equal
1212-- Prefer truncate shorthand
1313-- No manual dark: color overrides
1414-- Use cn() for conditional classes
1515-- No manual z-index on overlay components
77+- Use semantic colors. Prefer `bg-primary` and `text-muted-foreground` over raw color values.
88+- Use built-in variants first.
99+- Use `className` for layout only, not to override component styling.
1010+- Avoid `space-x-*` and `space-y-*`. Use `gap-*`.
1111+- Use `size-*` when width and height match.
1212+- Use `truncate` instead of the long overflow combo.
1313+- Do not add manual `dark:` overrides. Use semantic tokens.
1414+- Use `cn()` for conditional classes.
1515+- Do not set `z-index` manually on overlay components.
16161717----
1818-1919-## Semantic colors
2020-2121-**Incorrect:**
2222-2323-```tsx
2424-<div className="bg-blue-500 text-white">
2525- <p className="text-gray-600">Secondary text</p>
2626-</div>
2727-```
2828-2929-**Correct:**
1717+## Examples
30183119```tsx
3220<div className="bg-primary text-primary-foreground">
3321 <p className="text-muted-foreground">Secondary text</p>
3422</div>
3523```
3636-3737----
3838-3939-## No raw color values for status/state indicators
4040-4141-For positive, negative, or status indicators, use Badge variants, semantic tokens like `text-destructive`, or define custom CSS variables — don't reach for raw Tailwind colors.
4242-4343-**Incorrect:**
4444-4545-```tsx
4646-<span className="text-emerald-600">+20.1%</span>
4747-<span className="text-green-500">Active</span>
4848-<span className="text-red-600">-3.2%</span>
4949-```
5050-5151-**Correct:**
52245325```tsx
5426<Badge variant="secondary">+20.1%</Badge>
5555-<Badge>Active</Badge>
5627<span className="text-destructive">-3.2%</span>
5728```
5858-5959-If you need a success/positive color that doesn't exist as a semantic token, use a Badge variant or ask the user about adding a custom CSS variable to the theme (see [customization.md](../customization.md)).
6060-6161----
6262-6363-## Built-in variants first
6464-6565-**Incorrect:**
6666-6767-```tsx
6868-<Button className="border border-input bg-transparent hover:bg-accent">
6969- Click me
7070-</Button>
7171-```
7272-7373-**Correct:**
74297530```tsx
7631<Button variant="outline">Click me</Button>
7777-```
7878-7979----
8080-8181-## className for layout only
8282-8383-Use `className` for layout (e.g. `max-w-md`, `mx-auto`, `mt-4`), **not** for overriding component colors or typography. To change colors, use semantic tokens, built-in variants, or CSS variables.
8484-8585-**Incorrect:**
8686-8787-```tsx
8888-<Card className="bg-blue-100 text-blue-900 font-bold">
8989- <CardContent>Dashboard</CardContent>
9090-</Card>
9191-```
9292-9393-**Correct:**
9494-9595-```tsx
9632<Card className="max-w-md mx-auto">
9733 <CardContent>Dashboard</CardContent>
9834</Card>
9935```
10036101101-To customize a component's appearance, prefer these approaches in order:
102102-1. **Built-in variants** — `variant="outline"`, `variant="destructive"`, etc.
103103-2. **Semantic color tokens** — `bg-primary`, `text-muted-foreground`.
104104-3. **CSS variables** — define custom colors in the global CSS file (see [customization.md](../customization.md)).
105105-106106----
107107-108108-## No space-x-* / space-y-*
109109-110110-Use `gap-*` instead. `space-y-4` → `flex flex-col gap-4`. `space-x-2` → `flex gap-2`.
111111-11237```tsx
11338<div className="flex flex-col gap-4">
11439 <Input />
···11742</div>
11843```
11944120120----
121121-122122-## Prefer size-* over w-* h-* when equal
123123-124124-`size-10` not `w-10 h-10`. Applies to icons, avatars, skeletons, etc.
125125-126126----
127127-128128-## Prefer truncate shorthand
129129-130130-`truncate` not `overflow-hidden text-ellipsis whitespace-nowrap`.
131131-132132----
133133-134134-## No manual dark: color overrides
135135-136136-Use semantic tokens — they handle light/dark via CSS variables. `bg-background text-foreground` not `bg-white dark:bg-gray-950`.
137137-138138----
139139-140140-## Use cn() for conditional classes
141141-142142-Use the `cn()` utility from the project for conditional or merged class names. Don't write manual ternaries in className strings.
143143-144144-**Incorrect:**
145145-14645```tsx
147147-<div className={`flex items-center ${isActive ? "bg-primary text-primary-foreground" : "bg-muted"}`}>
4646+<Avatar className="size-10" />
14847```
149149-150150-**Correct:**
1514815249```tsx
153153-import { cn } from "@/lib/utils"
154154-15550<div className={cn("flex items-center", isActive ? "bg-primary text-primary-foreground" : "bg-muted")}>
15651```
15752158158----
159159-160160-## No manual z-index on overlay components
5353+## Overlay Rules
16154162162-`Dialog`, `Sheet`, `Drawer`, `AlertDialog`, `DropdownMenu`, `Popover`, `Tooltip`, `HoverCard` handle their own stacking. Never add `z-50` or `z-[999]`.
5555+`Dialog`, `Sheet`, `Drawer`, `AlertDialog`, `DropdownMenu`, `Popover`, `Tooltip`, and `HoverCard` manage stacking. Do not add `z-50` or similar.