this repo has no description
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

chore: compress shadcn skill docs

+333 -1152
+89 -91
skills/shadcn/SKILL.md
··· 1 1 --- 2 2 name: shadcn 3 - 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". 3 + 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`. 4 4 user-invocable: false 5 5 allowed-tools: Bash(npx shadcn@latest *), Bash(pnpm dlx shadcn@latest *), Bash(bunx --bun shadcn@latest *) 6 6 --- 7 7 8 8 # shadcn/ui 9 9 10 - A framework for building ui, components and design systems. Components are added as source code to the user's project via the CLI. 10 + A UI framework for components and design systems. The CLI adds source code to the user's project. 11 11 12 - > **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. 12 + > **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. 13 13 14 14 ## Current Project Context 15 15 ··· 17 17 !`npx shadcn@latest info --json` 18 18 ``` 19 19 20 - 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. 20 + Use the JSON for project config and installed components. Run `npx shadcn@latest docs <component>` for docs and example URLs. 21 21 22 22 ## Principles 23 23 24 - 1. **Use existing components first.** Use `npx shadcn@latest search` to check registries before writing custom UI. Check community registries too. 25 - 2. **Compose, don't reinvent.** Settings page = Tabs + Card + form controls. Dashboard = Sidebar + Card + Chart + Table. 26 - 3. **Use built-in variants before custom styles.** `variant="outline"`, `size="sm"`, etc. 27 - 4. **Use semantic colors.** `bg-primary`, `text-muted-foreground` — never raw values like `bg-blue-500`. 24 + 1. Use existing components first. Run `npx shadcn@latest search` before custom UI. Check community registries too. 25 + 2. Compose, don't reinvent. Settings page = Tabs + Card + form controls. Dashboard = Sidebar + Card + Chart + Table. 26 + 3. Use built-in variants before custom styles. `variant="outline"`, `size="sm"`, etc. 27 + 4. Use semantic colors. `bg-primary`, `text-muted-foreground` only. No raw values like `bg-blue-500`. 28 28 29 29 ## Critical Rules 30 30 31 - These rules are **always enforced**. Each links to a file with Incorrect/Correct code pairs. 31 + These rules are always on. Each links to incorrect and correct examples. 32 32 33 33 ### Styling & Tailwind → [styling.md](./rules/styling.md) 34 34 35 - - **`className` for layout, not styling.** Never override component colors or typography. 36 - - **No `space-x-*` or `space-y-*`.** Use `flex` with `gap-*`. For vertical stacks, `flex flex-col gap-*`. 37 - - **Use `size-*` when width and height are equal.** `size-10` not `w-10 h-10`. 38 - - **Use `truncate` shorthand.** Not `overflow-hidden text-ellipsis whitespace-nowrap`. 39 - - **No manual `dark:` color overrides.** Use semantic tokens (`bg-background`, `text-muted-foreground`). 40 - - **Use `cn()` for conditional classes.** Don't write manual template literal ternaries. 41 - - **No manual `z-index` on overlay components.** Dialog, Sheet, Popover, etc. handle their own stacking. 35 + - `className` for layout, not styling. Do not override component colors or typography. 36 + - No `space-x-*` or `space-y-*`. Use `flex` with `gap-*`. For vertical stacks, use `flex flex-col gap-*`. 37 + - Use `size-*` when width and height match. `size-10`, not `w-10 h-10`. 38 + - Use `truncate`. Do not write `overflow-hidden text-ellipsis whitespace-nowrap`. 39 + - No manual `dark:` color overrides. Use semantic tokens like `bg-background` and `text-muted-foreground`. 40 + - Use `cn()` for conditional classes. Do not write manual template ternaries. 41 + - No manual `z-index` on overlay components. Dialog, Sheet, Popover, and similar handle stacking. 42 42 43 43 ### Forms & Inputs → [forms.md](./rules/forms.md) 44 44 45 - - **Forms use `FieldGroup` + `Field`.** Never use raw `div` with `space-y-*` or `grid gap-*` for form layout. 46 - - **`InputGroup` uses `InputGroupInput`/`InputGroupTextarea`.** Never raw `Input`/`Textarea` inside `InputGroup`. 47 - - **Buttons inside inputs use `InputGroup` + `InputGroupAddon`.** 48 - - **Option sets (2–7 choices) use `ToggleGroup`.** Don't loop `Button` with manual active state. 49 - - **`FieldSet` + `FieldLegend` for grouping related checkboxes/radios.** Don't use a `div` with a heading. 50 - - **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. 45 + - Forms use `FieldGroup` + `Field`. Do not use raw `div` with `space-y-*` or `grid gap-*` for form layout. 46 + - `InputGroup` uses `InputGroupInput` and `InputGroupTextarea`. Do not place raw `Input` or `Textarea` inside `InputGroup`. 47 + - Buttons inside inputs use `InputGroup` + `InputGroupAddon`. 48 + - Option sets with 2 to 7 choices use `ToggleGroup`. Do not loop `Button` with manual active state. 49 + - Use `FieldSet` + `FieldLegend` for related checkboxes and radios. Do not use a `div` with a heading. 50 + - Validation uses `data-invalid` on `Field` and `aria-invalid` on the control. For disabled, use `data-disabled` on `Field` and `disabled` on the control. 51 51 52 52 ### Component Structure → [composition.md](./rules/composition.md) 53 53 54 - - **Items always inside their Group.** `SelectItem` → `SelectGroup`. `DropdownMenuItem` → `DropdownMenuGroup`. `CommandItem` → `CommandGroup`. 55 - - **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) 56 - - **Dialog, Sheet, and Drawer always need a Title.** `DialogTitle`, `SheetTitle`, `DrawerTitle` required for accessibility. Use `className="sr-only"` if visually hidden. 57 - - **Use full Card composition.** `CardHeader`/`CardTitle`/`CardDescription`/`CardContent`/`CardFooter`. Don't dump everything in `CardContent`. 58 - - **Button has no `isPending`/`isLoading`.** Compose with `Spinner` + `data-icon` + `disabled`. 59 - - **`TabsTrigger` must be inside `TabsList`.** Never render triggers directly in `Tabs`. 60 - - **`Avatar` always needs `AvatarFallback`.** For when the image fails to load. 54 + - Items stay inside their group. `SelectItem` → `SelectGroup`. `DropdownMenuItem` → `DropdownMenuGroup`. `CommandItem` → `CommandGroup`. 55 + - 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) 56 + - Dialog, Sheet, and Drawer need a Title. Use `DialogTitle`, `SheetTitle`, or `DrawerTitle`. Hide with `className="sr-only"` if needed. 57 + - Use full Card composition: `CardHeader`, `CardTitle`, `CardDescription`, `CardContent`, `CardFooter`. 58 + - Button has no `isPending` or `isLoading`. Compose with `Spinner` + `data-icon` + `disabled`. 59 + - `TabsTrigger` must stay inside `TabsList`. 60 + - `Avatar` needs `AvatarFallback`. 61 61 62 62 ### Use Components, Not Custom Markup → [composition.md](./rules/composition.md) 63 63 64 - - **Use existing components before custom markup.** Check if a component exists before writing a styled `div`. 65 - - **Callouts use `Alert`.** Don't build custom styled divs. 66 - - **Empty states use `Empty`.** Don't build custom empty state markup. 67 - - **Toast via `sonner`.** Use `toast()` from `sonner`. 68 - - **Use `Separator`** instead of `<hr>` or `<div className="border-t">`. 69 - - **Use `Skeleton`** for loading placeholders. No custom `animate-pulse` divs. 70 - - **Use `Badge`** instead of custom styled spans. 64 + - Use existing components before custom markup. Check if a component exists before writing a styled `div`. 65 + - Callouts use `Alert`. 66 + - Empty states use `Empty`. 67 + - Toasts use `sonner` and `toast()`. 68 + - Use `Separator` instead of `<hr>` or `<div className="border-t">`. 69 + - Use `Skeleton` for loading placeholders. No custom `animate-pulse` divs. 70 + - Use `Badge` instead of custom styled spans. 71 71 72 72 ### Icons → [icons.md](./rules/icons.md) 73 73 74 - - **Icons in `Button` use `data-icon`.** `data-icon="inline-start"` or `data-icon="inline-end"` on the icon. 75 - - **No sizing classes on icons inside components.** Components handle icon sizing via CSS. No `size-4` or `w-4 h-4`. 76 - - **Pass icons as objects, not string keys.** `icon={CheckIcon}`, not a string lookup. 74 + - Icons in `Button` use `data-icon`, either `inline-start` or `inline-end`. 75 + - Do not size icons inside components. Components handle icon sizing. No `size-4` or `w-4 h-4`. 76 + - Pass icons as objects, not string keys. `icon={CheckIcon}`, not a string lookup. 77 77 78 78 ### CLI 79 79 80 - - **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`. 81 - - **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. 80 + - Never decode preset codes or build preset URLs manually. Use `preset decode`, `preset url`, or `preset open`. For project-aware detection, use `preset resolve`. 81 + - Apply preset codes directly with the CLI. Use `apply <code>` for existing projects, or `init --preset <code>` when initializing. 82 82 83 83 ## Key Patterns 84 - 85 - These are the most common patterns that differentiate correct shadcn/ui code. For edge cases, see the linked rule files above. 86 84 87 85 ```tsx 88 86 // Form layout: FieldGroup + Field, not div + Label. ··· 139 137 140 138 ## Key Fields 141 139 142 - The injected project context contains these key fields: 140 + Injected project context fields: 143 141 144 - - **`aliases`** → use the actual alias prefix for imports (e.g. `@/`, `~/`), never hardcode. 145 - - **`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. 146 - - **`tailwindVersion`** → `"v4"` uses `@theme inline` blocks; `"v3"` uses `tailwind.config.js`. 147 - - **`tailwindCssFile`** → the global CSS file where custom CSS variables are defined. Always edit this file, never create a new one. 148 - - **`style`** → component visual treatment (e.g. `nova`, `vega`). 149 - - **`base`** → primitive library (`radix` or `base`). Affects component APIs and available props. 150 - - **`iconLibrary`** → determines icon imports. Use `lucide-react` for `lucide`, `@tabler/icons-react` for `tabler`, etc. Never assume `lucide-react`. 151 - - **`resolvedPaths`** → exact file-system destinations for components, utils, hooks, etc. 152 - - **`framework`** → routing and file conventions (e.g. Next.js App Router vs Vite SPA). 153 - - **`packageManager`** → use this for any non-shadcn dependency installs (e.g. `pnpm add date-fns` vs `npm install date-fns`). 154 - - **`preset`** → resolved preset code and values for the current project. Use `npx shadcn@latest preset resolve --json` when you only need preset information. 142 + - `aliases` means use the real alias prefix for imports, never hardcode. 143 + - `isRSC` means components with `useState`, `useEffect`, handlers, or browser APIs need `"use client"`. 144 + - `tailwindVersion` means `v4` uses `@theme inline` and `v3` uses `tailwind.config.js`. 145 + - `tailwindCssFile` is the global CSS file for custom CSS variables. Edit this file, never create a new one. 146 + - `style` is the component visual treatment, like `nova` or `vega`. 147 + - `base` is the primitive library, `radix` or `base`. It affects APIs and props. 148 + - `iconLibrary` controls icon imports. Use `lucide-react` for `lucide`, `@tabler/icons-react` for `tabler`, and so on. 149 + - `resolvedPaths` gives exact file destinations for components, utils, hooks, and more. 150 + - `framework` covers routing and file conventions, such as Next.js App Router or Vite SPA. 151 + - `packageManager` is the runner for non-shadcn installs, such as `pnpm add date-fns`. 152 + - `preset` is the resolved preset code and values for the current project. Use `preset resolve --json` for details. 155 153 156 154 See [cli.md — `info` command](./cli.md) for the full field reference. 157 155 158 156 ## Component Docs, Examples, and Usage 159 157 160 - 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. 158 + Run `npx shadcn@latest docs <component>` to get docs, examples, and API URLs. Fetch those URLs for actual content. 161 159 162 160 ```bash 163 161 npx shadcn@latest docs button dialog select 164 162 ``` 165 163 166 - **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. 164 + When creating, fixing, debugging, or using a component, always run `npx shadcn@latest docs` and fetch the URLs first. That keeps API usage correct. 167 165 168 166 ## Workflow 169 167 170 - 1. **Get project context** — already injected above. Run `npx shadcn@latest info` again if you need to refresh. 171 - 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. 172 - 3. **Find components** — `npx shadcn@latest search`. 173 - 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`. 174 - 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). 175 - 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. 176 - 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. 177 - 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. 178 - 9. **Switching presets** — Ask the user first: **overwrite**, **partial**, **merge**, or **skip**? 179 - - **Inspect current preset**: `npx shadcn@latest preset resolve`. Use `--json` when you need structured values. 180 - - **Inspect incoming preset**: `npx shadcn@latest preset decode <code>`. Use `preset url <code>` or `preset open <code>` to share or open the preset builder. 181 - - **Overwrite**: `npx shadcn@latest apply <code>`. Overwrites detected components, fonts, and CSS variables. 182 - - **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. 183 - - **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. 184 - - **Skip**: `npx shadcn@latest init --preset <code> --force --no-reinstall`. Only updates config and CSS, leaves components as-is. 185 - - **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. 168 + 1. Get project context. It is already injected above. Run `npx shadcn@latest info` if you need a refresh. 169 + 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. 170 + 3. Find components. Use `npx shadcn@latest search`. 171 + 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. 172 + 5. Install or update. Use `npx shadcn@latest add`. When updating, use `--dry-run` and `--diff` first. 173 + 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`. 174 + 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. 175 + 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. 176 + 9. Switching presets. Ask first: overwrite, partial, merge, or skip? 177 + - Inspect current preset: `npx shadcn@latest preset resolve`. Use `--json` for structured values. 178 + - Inspect incoming preset: `npx shadcn@latest preset decode <code>`. Use `preset url <code>` or `preset open <code>` to share or open the builder. 179 + - Overwrite: `npx shadcn@latest apply <code>`. 180 + - Partial: `npx shadcn@latest apply <code> --only theme,font`. Supported values are `theme` and `font`. 181 + - 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`. 182 + - Skip: `npx shadcn@latest init --preset <code> --force --no-reinstall`. Updates config and CSS only. 183 + - 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. 186 184 187 185 ## Updating Components 188 186 189 - 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.** 187 + When updating upstream while keeping local changes, use `--dry-run` and `--diff` for a smart merge. Never fetch raw files from GitHub manually. 190 188 191 - 1. Run `npx shadcn@latest add <component> --dry-run` to see all files that would be affected. 192 - 2. For each file, run `npx shadcn@latest add <component> --diff <file>` to see what changed upstream vs local. 193 - 3. Decide per file based on the diff: 194 - - No local changes → safe to overwrite. 195 - - Has local changes → read the local file, analyze the diff, and apply upstream updates while preserving local modifications. 196 - - User says "just update everything" → use `--overwrite`, but confirm first. 197 - 4. **Never use `--overwrite` without the user's explicit approval.** 189 + 1. Run `npx shadcn@latest add <component> --dry-run` to see affected files. 190 + 2. For each file, run `npx shadcn@latest add <component> --diff <file>` to compare upstream and local. 191 + 3. Decide per file: 192 + - No local changes: overwrite safely. 193 + - Has local changes: read the local file, analyze the diff, and apply upstream updates while keeping local changes. 194 + - User says update everything: use `--overwrite`, but confirm first. 195 + 4. Never use `--overwrite` without explicit approval. 198 196 199 197 ## Quick Reference 200 198 ··· 241 239 # Get component docs and example URLs. 242 240 npx shadcn@latest docs button dialog select 243 241 244 - # View registry item details (for items not yet installed). 242 + # View registry item details for items not yet installed. 245 243 npx shadcn@latest view @shadcn/button 246 244 ``` 247 245 248 246 **Named presets:** `nova`, `vega`, `maia`, `lyra`, `mira`, `luma` 249 - **Templates:** `next`, `vite`, `start`, `react-router`, `astro` (all support `--monorepo`) and `laravel` (not supported for monorepo) 250 - **Preset codes:** Version-prefixed base62 strings (e.g. `a2r6bw` or `b0`), from [ui.shadcn.com](https://ui.shadcn.com). 247 + **Templates:** `next`, `vite`, `start`, `react-router`, `astro` all support `--monorepo`, and `laravel` does not. 248 + **Preset codes:** Version-prefixed base62 strings like `a2r6bw` or `b0`, from [ui.shadcn.com](https://ui.shadcn.com). 251 249 252 250 ## Detailed References 253 251 254 - - [rules/forms.md](./rules/forms.md) — FieldGroup, Field, InputGroup, ToggleGroup, FieldSet, validation states 255 - - [rules/composition.md](./rules/composition.md) — Groups, overlays, Card, Tabs, Avatar, Alert, Empty, Toast, Separator, Skeleton, Badge, Button loading 256 - - [rules/icons.md](./rules/icons.md) — data-icon, icon sizing, passing icons as objects 257 - - [rules/styling.md](./rules/styling.md) — Semantic colors, variants, className, spacing, size, truncate, dark mode, cn(), z-index 258 - - [rules/base-vs-radix.md](./rules/base-vs-radix.md) — asChild vs render, Select, ToggleGroup, Slider, Accordion 259 - - [cli.md](./cli.md) — Commands, flags, presets, templates 260 - - [customization.md](./customization.md) — Theming, CSS variables, extending components 252 + - [rules/forms.md](./rules/forms.md) - FieldGroup, Field, InputGroup, ToggleGroup, FieldSet, validation states 253 + - [rules/composition.md](./rules/composition.md) - Groups, overlays, Card, Tabs, Avatar, Alert, Empty, Toast, Separator, Skeleton, Badge, Button loading 254 + - [rules/icons.md](./rules/icons.md) - data-icon, icon sizing, passing icons as objects 255 + - [rules/styling.md](./rules/styling.md) - semantic colors, variants, className, spacing, size, truncate, dark mode, cn(), z-index 256 + - [rules/base-vs-radix.md](./rules/base-vs-radix.md) - asChild vs render, Select, ToggleGroup, Slider, Accordion 257 + - [cli.md](./cli.md) - Commands, flags, presets, templates 258 + - [customization.md](./customization.md) - Theming, CSS variables, extending components
+124 -186
skills/shadcn/cli.md
··· 1 1 # shadcn CLI Reference 2 2 3 - Configuration is read from `components.json`. 4 - 5 - > **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. 6 - 7 - > **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. 8 - 9 - ## Contents 10 - 11 - - Commands: init, apply, add (dry-run, smart merge), search, view, docs, info, build 12 - - Templates: next, vite, start, react-router, astro 13 - - Presets: named, code, URL formats and fields 14 - - Switching presets 3 + Configuration comes from `components.json`. 15 4 16 - --- 5 + > **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`. 6 + > **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. 17 7 18 8 ## Commands 19 9 20 - ### `init` — Initialize or create a project 10 + ### `init` - Initialize or create a project 21 11 22 12 ```bash 23 13 npx shadcn@latest init [components...] [options] 24 14 ``` 25 15 26 - Initializes shadcn/ui in an existing project or creates a new project (when `--name` is provided). Optionally installs components in the same step. 16 + Creates or initializes a shadcn/ui project. Can install components at the same time. 27 17 28 - | Flag | Short | Description | Default | 29 - | ----------------------- | ----- | --------------------------------------------------------- | ------- | 30 - | `--template <template>` | `-t` | Template (next, start, vite, next-monorepo, react-router) | — | 31 - | `--preset [name]` | `-p` | Preset configuration (named, code, or URL) | — | 32 - | `--yes` | `-y` | Skip confirmation prompt | `true` | 33 - | `--defaults` | `-d` | Use defaults (`--template=next --preset=base-nova`) | `false` | 34 - | `--force` | `-f` | Force overwrite existing configuration | `false` | 35 - | `--cwd <cwd>` | `-c` | Working directory | current | 36 - | `--name <name>` | `-n` | Name for new project | — | 37 - | `--silent` | `-s` | Mute output | `false` | 38 - | `--rtl` | | Enable RTL support | — | 39 - | `--reinstall` | | Re-install existing UI components | `false` | 40 - | `--monorepo` | | Scaffold a monorepo project | — | 41 - | `--no-monorepo` | | Skip the monorepo prompt | — | 18 + | Flag | Short | Description | Default | 19 + | --- | --- | --- | --- | 20 + | `--template <template>` | `-t` | Template (`next`, `start`, `vite`, `next-monorepo`, `react-router`) | - | 21 + | `--preset [name]` | `-p` | Preset config (`named`, `code`, or `URL`) | - | 22 + | `--yes` | `-y` | Skip prompt | `true` | 23 + | `--defaults` | `-d` | Use defaults (`--template=next --preset=base-nova`) | `false` | 24 + | `--force` | `-f` | Overwrite existing config | `false` | 25 + | `--cwd <cwd>` | `-c` | Working directory | current | 26 + | `--name <name>` | `-n` | New project name | - | 27 + | `--silent` | `-s` | Mute output | `false` | 28 + | `--rtl` | | Enable RTL | - | 29 + | `--reinstall` | | Re-install existing UI components | `false` | 30 + | `--monorepo` | | Scaffold monorepo | - | 31 + | `--no-monorepo` | | Skip monorepo prompt | - | 42 32 43 - `npx shadcn@latest create` is an alias for `npx shadcn@latest init`. 33 + `npx shadcn@latest create` aliases `init`. 44 34 45 - ### `apply` — Apply a preset to an existing project 35 + ### `apply` - Apply a preset 46 36 47 37 ```bash 48 38 npx shadcn@latest apply [preset] [options] 49 39 ``` 50 40 51 - Applies a preset to an existing project, overwriting preset-driven config, fonts, CSS variables, and detected UI components. 41 + Applies a preset to an existing project and overwrites preset-driven config, fonts, CSS variables, and detected UI components. 52 42 53 - | Flag | Short | Description | Default | 54 - | ------------------- | ----- | ------------------------------------------ | ------- | 55 - | `--preset <preset>` | — | Preset configuration (named, code, or URL) | — | 56 - | `--yes` | `-y` | Skip confirmation prompt | `false` | 57 - | `--cwd <cwd>` | `-c` | Working directory | current | 58 - | `--silent` | `-s` | Mute output | `false` | 43 + | Flag | Short | Description | Default | 44 + | --- | --- | --- | --- | 45 + | `--preset <preset>` | - | Preset config (`named`, `code`, or `URL`) | - | 46 + | `--yes` | `-y` | Skip prompt | `false` | 47 + | `--cwd <cwd>` | `-c` | Working directory | current | 48 + | `--silent` | `-s` | Mute output | `false` | 59 49 60 - `[preset]` is a shorthand for `--preset <preset>`. If both are provided, they must match. 61 - If no preset is provided, the CLI offers to open the custom preset builder on `ui.shadcn.com/create`. 50 + `[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`. 62 51 63 - ### `add` — Add components 52 + ### `add` - Add components 64 53 65 - > **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. 54 + > **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. 66 55 67 56 ```bash 68 57 npx shadcn@latest add [components...] [options] 69 58 ``` 70 59 71 - Accepts component names, registry-prefixed names (`@magicui/shimmer-button`), URLs, or local paths. 60 + Accepts component names, registry names like `@magicui/shimmer-button`, URLs, or local paths. 72 61 73 - | Flag | Short | Description | Default | 74 - | --------------- | ----- | -------------------------------------------------------------------------------------------------------------------- | ------- | 75 - | `--yes` | `-y` | Skip confirmation prompt | `false` | 76 - | `--overwrite` | `-o` | Overwrite existing files | `false` | 77 - | `--cwd <cwd>` | `-c` | Working directory | current | 78 - | `--all` | `-a` | Add all available components | `false` | 79 - | `--path <path>` | `-p` | Target path for the component | — | 80 - | `--silent` | `-s` | Mute output | `false` | 81 - | `--dry-run` | | Preview all changes without writing files | `false` | 82 - | `--diff [path]` | | Show diffs. Without a path, shows the first 5 files. With a path, shows that file only (implies `--dry-run`) | — | 83 - | `--view [path]` | | Show file contents. Without a path, shows the first 5 files. With a path, shows that file only (implies `--dry-run`) | — | 62 + | Flag | Short | Description | Default | 63 + | --- | --- | --- | --- | 64 + | `--yes` | `-y` | Skip prompt | `false` | 65 + | `--overwrite` | `-o` | Overwrite files | `false` | 66 + | `--cwd <cwd>` | `-c` | Working directory | current | 67 + | `--all` | `-a` | Add all components | `false` | 68 + | `--path <path>` | `-p` | Target path | - | 69 + | `--silent` | `-s` | Mute output | `false` | 70 + | `--dry-run` | | Preview changes without writing | `false` | 71 + | `--diff [path]` | | Show diffs. No path shows first 5 files. With path shows only that file. Implies `--dry-run` | - | 72 + | `--view [path]` | | Show file contents. No path shows first 5 files. With path shows only that file. Implies `--dry-run` | - | 84 73 85 - #### Dry-Run Mode 74 + 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. 86 75 87 - Use `--dry-run` to preview what `add` would do without writing any files. `--diff` and `--view` both imply `--dry-run`. 88 - 89 - ```bash 90 - # Preview all changes. 91 - npx shadcn@latest add button --dry-run 76 + See [Updating Components in SKILL.md](./SKILL.md#updating-components) for smart merge workflow. 92 77 93 - # Show diffs for all files (top 5). 94 - npx shadcn@latest add button --diff 95 - 96 - # Show the diff for a specific file. 97 - npx shadcn@latest add button --diff button.tsx 98 - 99 - # Show contents for all files (top 5). 100 - npx shadcn@latest add button --view 101 - 102 - # Show the full content of a specific file. 103 - npx shadcn@latest add button --view button.tsx 104 - 105 - # Works with URLs too. 106 - npx shadcn@latest add https://api.npoint.io/abc123 --dry-run 107 - 108 - # CSS diffs. 109 - npx shadcn@latest add button --diff globals.css 110 - ``` 111 - 112 - **When to use dry-run:** 113 - 114 - - When the user asks "what files will this add?" or "what will this change?" — use `--dry-run`. 115 - - Before overwriting existing components — use `--diff` to preview the changes first. 116 - - When the user wants to inspect component source code without installing — use `--view`. 117 - - When checking what CSS changes would be made to `globals.css` — use `--diff globals.css`. 118 - - When the user asks to review or audit third-party registry code before installing — use `--view` to inspect the source. 119 - 120 - > **`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. 121 - 122 - #### Smart Merge from Upstream 123 - 124 - See [Updating Components in SKILL.md](./SKILL.md#updating-components) for the full workflow. 125 - 126 - ### `search` — Search registries 78 + ### `search` - Search registries 127 79 128 80 ```bash 129 81 npx shadcn@latest search <registries...> [options] 130 82 ``` 131 83 132 - Fuzzy search across registries. Also aliased as `npx shadcn@latest list`. Without `-q`, lists all items. 84 + Fuzzy search across registries. Aliased as `list`. Without `-q`, lists all items. 133 85 134 - | Flag | Short | Description | Default | 135 - | ------------------- | ----- | ---------------------- | ------- | 136 - | `--query <query>` | `-q` | Search query | — | 137 - | `--limit <number>` | `-l` | Max items per registry | `100` | 138 - | `--offset <number>` | `-o` | Items to skip | `0` | 139 - | `--cwd <cwd>` | `-c` | Working directory | current | 86 + | Flag | Short | Description | Default | 87 + | --- | --- | --- | --- | 88 + | `--query <query>` | `-q` | Search query | - | 89 + | `--limit <number>` | `-l` | Max items per registry | `100` | 90 + | `--offset <number>` | `-o` | Items to skip | `0` | 91 + | `--cwd <cwd>` | `-c` | Working directory | current | 140 92 141 - ### `view` — View item details 93 + ### `view` - View item details 142 94 143 95 ```bash 144 96 npx shadcn@latest view <items...> [options] 145 97 ``` 146 98 147 - Displays item info including file contents. Example: `npx shadcn@latest view @shadcn/button`. 99 + Shows item info and file contents. Example: `npx shadcn@latest view @shadcn/button`. 148 100 149 - ### `docs` — Get component documentation URLs 101 + ### `docs` - Get documentation URLs 150 102 151 103 ```bash 152 104 npx shadcn@latest docs <components...> [options] 153 105 ``` 154 106 155 - Outputs resolved URLs for component documentation, examples, and API references. Accepts one or more component names. Fetch the URLs to get the actual content. 107 + Returns docs, examples, and API URLs. Fetch those URLs for actual content. 156 108 157 - Example output for `npx shadcn@latest docs input button`: 109 + Example: 158 110 111 + ```bash 112 + npx shadcn@latest docs input button 159 113 ``` 160 - base radix 161 114 162 - input 163 - docs https://ui.shadcn.com/docs/components/radix/input 164 - examples https://raw.githubusercontent.com/.../examples/input-example.tsx 115 + Some components also include an `api` link for the underlying library. 165 116 166 - button 167 - docs https://ui.shadcn.com/docs/components/radix/button 168 - examples https://raw.githubusercontent.com/.../examples/button-example.tsx 169 - ``` 170 - 171 - Some components include an `api` link to the underlying library (e.g. `cmdk` for the command component). 172 - 173 - ### `diff` — Check for updates 117 + ### `diff` - Check for updates 174 118 175 119 Do not use this command. Use `npx shadcn@latest add --diff` instead. 176 120 177 - ### `info` — Project information 121 + ### `info` - Project information 178 122 179 123 ```bash 180 124 npx shadcn@latest info [options] 181 125 ``` 182 126 183 - Displays project info and `components.json` configuration. Run this first to discover the project's framework, aliases, Tailwind version, and resolved paths. 127 + Shows project info and `components.json`. Run this first to discover framework, aliases, Tailwind version, and resolved paths. 184 128 185 - | Flag | Short | Description | Default | 186 - | ------------- | ----- | ----------------- | ------- | 187 - | `--cwd <cwd>` | `-c` | Working directory | current | 129 + | Flag | Short | Description | Default | 130 + | --- | --- | --- | --- | 131 + | `--cwd <cwd>` | `-c` | Working directory | current | 188 132 189 - **Project Info fields:** 133 + `info` fields: 190 134 191 - | Field | Type | Meaning | 192 - | -------------------- | --------- | ------------------------------------------------------------------ | 193 - | `framework` | `string` | Detected framework (`next`, `vite`, `react-router`, `start`, etc.) | 194 - | `frameworkVersion` | `string` | Framework version (e.g. `15.2.4`) | 195 - | `isSrcDir` | `boolean` | Whether the project uses a `src/` directory | 196 - | `isRSC` | `boolean` | Whether React Server Components are enabled | 197 - | `isTsx` | `boolean` | Whether the project uses TypeScript | 198 - | `tailwindVersion` | `string` | `"v3"` or `"v4"` | 199 - | `tailwindConfigFile` | `string` | Path to the Tailwind config file | 200 - | `tailwindCssFile` | `string` | Path to the global CSS file | 201 - | `aliasPrefix` | `string` | Import alias prefix (e.g. `@`, `~`, `@/`) | 202 - | `packageManager` | `string` | Detected package manager (`npm`, `pnpm`, `yarn`, `bun`) | 135 + | Field | Type | Meaning | 136 + | --- | --- | --- | 137 + | `framework` | `string` | Framework (`next`, `vite`, `react-router`, `start`, etc.) | 138 + | `frameworkVersion` | `string` | Framework version | 139 + | `isSrcDir` | `boolean` | Uses `src/` dir | 140 + | `isRSC` | `boolean` | React Server Components enabled | 141 + | `isTsx` | `boolean` | Uses TypeScript | 142 + | `tailwindVersion` | `string` | `v3` or `v4` | 143 + | `tailwindConfigFile` | `string` | Tailwind config path | 144 + | `tailwindCssFile` | `string` | Global CSS path | 145 + | `aliasPrefix` | `string` | Import alias prefix | 146 + | `packageManager` | `string` | `npm`, `pnpm`, `yarn`, or `bun` | 203 147 204 - **Components.json fields:** 148 + `components.json` fields: 205 149 206 - | Field | Type | Meaning | 207 - | -------------------- | --------- | ------------------------------------------------------------------------------------------ | 208 - | `base` | `string` | Primitive library (`radix` or `base`) — determines component APIs and available props | 209 - | `style` | `string` | Visual style (e.g. `nova`, `vega`) | 210 - | `rsc` | `boolean` | RSC flag from config | 211 - | `tsx` | `boolean` | TypeScript flag | 212 - | `tailwind.config` | `string` | Tailwind config path | 213 - | `tailwind.css` | `string` | Global CSS path — this is where custom CSS variables go | 214 - | `iconLibrary` | `string` | Icon library — determines icon import package (e.g. `lucide-react`, `@tabler/icons-react`) | 215 - | `aliases.components` | `string` | Component import alias (e.g. `@/components`) | 216 - | `aliases.utils` | `string` | Utils import alias (e.g. `@/lib/utils`) | 217 - | `aliases.ui` | `string` | UI component alias (e.g. `@/components/ui`) | 218 - | `aliases.lib` | `string` | Lib alias (e.g. `@/lib`) | 219 - | `aliases.hooks` | `string` | Hooks alias (e.g. `@/hooks`) | 220 - | `resolvedPaths` | `object` | Absolute file-system paths for each alias | 221 - | `registries` | `object` | Configured custom registries | 150 + | Field | Type | Meaning | 151 + | --- | --- | --- | 152 + | `base` | `string` | `radix` or `base` | 153 + | `style` | `string` | Visual style | 154 + | `rsc` | `boolean` | RSC flag | 155 + | `tsx` | `boolean` | TypeScript flag | 156 + | `tailwind.config` | `string` | Tailwind config path | 157 + | `tailwind.css` | `string` | Global CSS path | 158 + | `iconLibrary` | `string` | Icon package | 159 + | `aliases.components` | `string` | Components alias | 160 + | `aliases.utils` | `string` | Utils alias | 161 + | `aliases.ui` | `string` | UI alias | 162 + | `aliases.lib` | `string` | Lib alias | 163 + | `aliases.hooks` | `string` | Hooks alias | 164 + | `resolvedPaths` | `object` | Absolute paths | 165 + | `registries` | `object` | Custom registries | 222 166 223 - **Links fields:** 167 + `info` also includes `Links` with templated URLs. For resolved URLs, use `docs <component>`. 224 168 225 - 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. 226 - 227 - ### `build` — Build a custom registry 169 + ### `build` - Build a custom registry 228 170 229 171 ```bash 230 172 npx shadcn@latest build [registry] [options] 231 173 ``` 232 174 233 - Builds `registry.json` into individual JSON files for distribution. Default input: `./registry.json`, default output: `./public/r`. 175 + Builds `registry.json` into distributable JSON files. Default input `./registry.json`, default output `./public/r`. 234 176 235 - | Flag | Short | Description | Default | 236 - | ----------------- | ----- | ----------------- | ------------ | 237 - | `--output <path>` | `-o` | Output directory | `./public/r` | 238 - | `--cwd <cwd>` | `-c` | Working directory | current | 239 - 240 - --- 177 + | Flag | Short | Description | Default | 178 + | --- | --- | --- | --- | 179 + | `--output <path>` | `-o` | Output directory | `./public/r` | 180 + | `--cwd <cwd>` | `-c` | Working directory | current | 241 181 242 182 ## Templates 243 183 244 - | Value | Framework | Monorepo support | 245 - | -------------- | -------------- | ---------------- | 246 - | `next` | Next.js | Yes | 247 - | `vite` | Vite | Yes | 248 - | `start` | TanStack Start | Yes | 249 - | `react-router` | React Router | Yes | 250 - | `astro` | Astro | Yes | 251 - | `laravel` | Laravel | No | 184 + | Value | Framework | Monorepo support | 185 + | --- | --- | --- | 186 + | `next` | Next.js | Yes | 187 + | `vite` | Vite | Yes | 188 + | `start` | TanStack Start | Yes | 189 + | `react-router` | React Router | Yes | 190 + | `astro` | Astro | Yes | 191 + | `laravel` | Laravel | No | 252 192 253 - 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. 254 - 255 - --- 193 + All templates support monorepo scaffolding via `--monorepo`. If neither `--monorepo` nor `--no-monorepo` is passed, the CLI prompts. Laravel does not support monorepo scaffolding. 256 194 257 195 ## Presets 258 196 259 - Three ways to specify a preset via `--preset`: 197 + Three preset forms: 260 198 261 - 1. **Named:** `--preset nova` or `--preset lyra` 262 - 2. **Code:** `--preset a2r6bw` (version-prefixed base62 string, e.g. `a2r6bw` or `b0`) 263 - 3. **URL:** `--preset "https://ui.shadcn.com/init?base=radix&style=nova&..."` 199 + 1. Named: `--preset nova` or `--preset lyra` 200 + 2. Code: `--preset a2r6bw` 201 + 3. URL: `--preset "https://ui.shadcn.com/init?base=radix&style=nova&..."` 264 202 265 - > **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. 266 - > Use `npx shadcn@latest apply --preset <code>` when overwriting an existing project's preset. 203 + > **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. 204 + > Use `apply --preset <code>` when overwriting an existing preset. 267 205 268 206 ## Switching Presets 269 207 270 - Ask the user first: **overwrite**, **merge**, or **skip** existing components? 208 + Ask first: **overwrite**, **merge**, or **skip** existing components? 271 209 272 - - **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. 273 - - **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. 274 - - **Skip** → `npx shadcn@latest init --preset <code> --force --no-reinstall`. Only updates config and CSS variables, leaves existing components as-is. 210 + - **Overwrite / Re-install** → `npx shadcn@latest apply --preset <code>`. 211 + - **Merge** → `npx shadcn@latest init --preset <code> --force --no-reinstall`, then run `npx shadcn@latest info` and smart merge each component one by one. 212 + - **Skip** → `npx shadcn@latest init --preset <code> --force --no-reinstall`. 275 213 276 - 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. 214 + 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
··· 1 1 # Customization & Theming 2 2 3 - Components reference semantic CSS variable tokens. Change the variables to change every component. 4 - 5 - ## Contents 6 - 7 - - How it works (CSS variables → Tailwind utilities → components) 8 - - Color variables and OKLCH format 9 - - Dark mode setup 10 - - Changing the theme (presets, CSS variables) 11 - - Adding custom colors (Tailwind v3 and v4) 12 - - Border radius 13 - - Customizing components (variants, className, wrappers) 14 - - Checking for updates 15 - 16 - --- 3 + Components use semantic CSS variables. Change variables to change every component. 17 4 18 5 ## How It Works 19 6 20 - 1. CSS variables defined in `:root` (light) and `.dark` (dark mode). 21 - 2. Tailwind maps them to utilities: `bg-primary`, `text-muted-foreground`, etc. 22 - 3. Components use these utilities — changing a variable changes all components that reference it. 23 - 24 - --- 7 + 1. Define CSS vars in `:root` and `.dark`. 8 + 2. Tailwind maps them to utilities like `bg-primary` and `text-muted-foreground`. 9 + 3. Components consume those utilities, so one var change updates all consumers. 25 10 26 11 ## Color Variables 27 12 28 - Every color follows the `name` / `name-foreground` convention. The base variable is for backgrounds, `-foreground` is for text/icons on that background. 13 + Use `name` and `name-foreground` pairs. Base var is the background. `-foreground` is text/icons on that background. 29 14 30 - | Variable | Purpose | 31 - | -------------------------------------------- | -------------------------------- | 32 - | `--background` / `--foreground` | Page background and default text | 33 - | `--card` / `--card-foreground` | Card surfaces | 34 - | `--primary` / `--primary-foreground` | Primary buttons and actions | 35 - | `--secondary` / `--secondary-foreground` | Secondary actions | 36 - | `--muted` / `--muted-foreground` | Muted/disabled states | 37 - | `--accent` / `--accent-foreground` | Hover and accent states | 38 - | `--destructive` / `--destructive-foreground` | Error and destructive actions | 39 - | `--border` | Default border color | 40 - | `--input` | Form input borders | 41 - | `--ring` | Focus ring color | 42 - | `--chart-1` through `--chart-5` | Chart/data visualization | 43 - | `--sidebar-*` | Sidebar-specific colors | 44 - | `--surface` / `--surface-foreground` | Secondary surface | 15 + | Variable | Purpose | 16 + | --- | --- | 17 + | `--background` / `--foreground` | Page background and default text | 18 + | `--card` / `--card-foreground` | Card surfaces | 19 + | `--primary` / `--primary-foreground` | Primary actions | 20 + | `--secondary` / `--secondary-foreground` | Secondary actions | 21 + | `--muted` / `--muted-foreground` | Muted and disabled states | 22 + | `--accent` / `--accent-foreground` | Hover and accent states | 23 + | `--destructive` / `--destructive-foreground` | Errors and destructive actions | 24 + | `--border` | Default border color | 25 + | `--input` | Input borders | 26 + | `--ring` | Focus ring | 27 + | `--chart-1` to `--chart-5` | Chart colors | 28 + | `--sidebar-*` | Sidebar colors | 29 + | `--surface` / `--surface-foreground` | Secondary surface | 45 30 46 - Colors use OKLCH: `--primary: oklch(0.205 0 0)` where values are lightness (0–1), chroma (0 = gray), and hue (0–360). 47 - 48 - --- 31 + Colors use OKLCH, for example `--primary: oklch(0.205 0 0)`. 49 32 50 33 ## Dark Mode 51 34 52 - Class-based toggle via `.dark` on the root element. In Next.js, use `next-themes`: 35 + Use class-based dark mode with `.dark` on the root. In Next.js, use `next-themes`: 53 36 54 37 ```tsx 55 38 import { ThemeProvider } from "next-themes" ··· 59 42 </ThemeProvider> 60 43 ``` 61 44 62 - --- 63 - 64 45 ## Changing the Theme 65 46 66 47 ```bash 67 - # Apply a preset code from ui.shadcn.com. 68 48 npx shadcn@latest apply --preset a2r6bw 69 - 70 - # Positional shorthand also works. 71 49 npx shadcn@latest apply a2r6bw 72 - 73 - # Switch to a named preset and overwrite existing components. 74 50 npx shadcn@latest apply --preset nova 75 - 76 - # Preserve existing components instead. 77 51 npx shadcn@latest init --preset nova --force --no-reinstall 78 - 79 - # Use a custom theme URL. 80 52 npx shadcn@latest apply --preset "https://ui.shadcn.com/init?base=radix&style=nova&theme=blue&..." 81 53 ``` 82 54 83 55 Or edit CSS variables directly in `globals.css`. 84 - 85 - --- 86 56 87 57 ## Adding Custom Colors 88 58 89 - Add variables to the file at `tailwindCssFile` from `npx shadcn@latest info` (typically `globals.css`). Never create a new CSS file for this. 59 + Add vars to `tailwindCssFile` from `npx shadcn@latest info`. Do not create a new CSS file. 90 60 91 61 ```css 92 - /* 1. Define in the global CSS file. */ 93 62 :root { 94 63 --warning: oklch(0.84 0.16 84); 95 64 --warning-foreground: oklch(0.28 0.07 46); ··· 100 69 } 101 70 ``` 102 71 72 + Tailwind v4: 73 + 103 74 ```css 104 - /* 2a. Register with Tailwind v4 (@theme inline). */ 105 75 @theme inline { 106 76 --color-warning: var(--warning); 107 77 --color-warning-foreground: var(--warning-foreground); 108 78 } 109 79 ``` 110 80 111 - When `tailwindVersion` is `"v3"` (check via `npx shadcn@latest info`), register in `tailwind.config.js` instead: 81 + Tailwind v3: 112 82 113 83 ```js 114 - // 2b. Register with Tailwind v3 (tailwind.config.js). 115 84 module.exports = { 116 85 theme: { 117 86 extend: { 118 87 colors: { 119 88 warning: "oklch(var(--warning) / <alpha-value>)", 120 - "warning-foreground": 121 - "oklch(var(--warning-foreground) / <alpha-value>)", 89 + "warning-foreground": "oklch(var(--warning-foreground) / <alpha-value>)", 122 90 }, 123 91 }, 124 92 }, 125 93 } 126 94 ``` 127 95 96 + Use it in components: 97 + 128 98 ```tsx 129 - // 3. Use in components. 130 99 <div className="bg-warning text-warning-foreground">Warning</div> 131 100 ``` 132 101 133 - --- 134 - 135 102 ## Border Radius 136 103 137 - `--radius` controls border radius globally. Components derive values from it (`rounded-lg` = `var(--radius)`, `rounded-md` = `calc(var(--radius) - 2px)`). 138 - 139 - --- 104 + `--radius` controls border radius globally. `rounded-lg` and `rounded-md` derive from it. 140 105 141 106 ## Customizing Components 142 107 143 - See also: [rules/styling.md](./rules/styling.md) for Incorrect/Correct examples. 144 - 145 - Prefer these approaches in order: 146 - 147 - ### 1. Built-in variants 148 - 149 - ```tsx 150 - <Button variant="outline" size="sm"> 151 - Click 152 - </Button> 153 - ``` 154 - 155 - ### 2. Tailwind classes via `className` 156 - 157 - ```tsx 158 - <Card className="mx-auto max-w-md">...</Card> 159 - ``` 160 - 161 - ### 3. Add a new variant 162 - 163 - Edit the component source to add a variant via `cva`: 164 - 165 - ```tsx 166 - // components/ui/button.tsx 167 - warning: "bg-warning text-warning-foreground hover:bg-warning/90", 168 - ``` 169 - 170 - ### 4. Wrapper components 171 - 172 - Compose shadcn/ui primitives into higher-level components: 173 - 174 - ```tsx 175 - export function ConfirmDialog({ title, description, onConfirm, children }) { 176 - return ( 177 - <AlertDialog> 178 - <AlertDialogTrigger asChild>{children}</AlertDialogTrigger> 179 - <AlertDialogContent> 180 - <AlertDialogHeader> 181 - <AlertDialogTitle>{title}</AlertDialogTitle> 182 - <AlertDialogDescription>{description}</AlertDialogDescription> 183 - </AlertDialogHeader> 184 - <AlertDialogFooter> 185 - <AlertDialogCancel>Cancel</AlertDialogCancel> 186 - <AlertDialogAction onClick={onConfirm}>Confirm</AlertDialogAction> 187 - </AlertDialogFooter> 188 - </AlertDialogContent> 189 - </AlertDialog> 190 - ) 191 - } 192 - ``` 193 - 194 - --- 108 + 1. Built-in variants. 109 + 2. `className` for layout. 110 + 3. Add a new variant in the component source. 111 + 4. Wrapper components for higher-level composition. 195 112 196 113 ## Checking for Updates 197 114 198 115 ```bash 199 116 npx shadcn@latest add button --diff 117 + npx shadcn@latest add button --dry-run 118 + npx shadcn@latest add button --diff button.tsx 200 119 ``` 201 120 202 - To preview exactly what would change before updating, use `--dry-run` and `--diff`: 203 - 204 - ```bash 205 - npx shadcn@latest add button --dry-run # see all affected files 206 - npx shadcn@latest add button --diff button.tsx # see the diff for a specific file 207 - ``` 121 + Use `--dry-run` and `--diff` before updating. 208 122 209 - See [Updating Components in SKILL.md](./SKILL.md#updating-components) for the full smart merge workflow. 123 + See [Updating Components in SKILL.md](./SKILL.md#updating-components).
+16 -56
skills/shadcn/mcp.md
··· 1 1 # shadcn MCP Server 2 2 3 - The CLI includes an MCP server that lets AI assistants search, browse, view, and install components from registries. 4 - 5 - --- 3 + The CLI includes an MCP server for registry search, browsing, and install flows. 6 4 7 5 ## Setup 8 6 9 7 ```bash 10 - shadcn mcp # start the MCP server (stdio) 11 - shadcn mcp init # write config for your editor 8 + shadcn mcp 9 + shadcn mcp init 12 10 ``` 13 11 14 - Editor config files: 12 + Editor configs: 15 13 16 14 | Editor | Config file | 17 - |--------|------------| 15 + | --- | --- | 18 16 | Claude Code | `.mcp.json` | 19 17 | Cursor | `.cursor/mcp.json` | 20 18 | VS Code | `.vscode/mcp.json` | 21 19 | OpenCode | `opencode.json` | 22 - | Codex | `~/.codex/config.toml` (manual) | 23 - 24 - --- 20 + | Codex | `~/.codex/config.toml` | 25 21 26 22 ## Tools 27 23 28 - > **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. 29 - 30 - ### `shadcn:get_project_registries` 31 - 32 - Returns registry names from `components.json`. Errors if no `components.json` exists. 33 - 34 - **Input:** none 35 - 36 - ### `shadcn:list_items_in_registries` 37 - 38 - Lists all items from one or more registries. 39 - 40 - **Input:** `registries` (string[]), `limit` (number, optional), `offset` (number, optional) 41 - 42 - ### `shadcn:search_items_in_registries` 43 - 44 - Fuzzy search across registries. 45 - 46 - **Input:** `registries` (string[]), `query` (string), `limit` (number, optional), `offset` (number, optional) 47 - 48 - ### `shadcn:view_items_in_registries` 49 - 50 - View item details including full file contents. 51 - 52 - **Input:** `items` (string[]) — e.g. `["@shadcn/button", "@shadcn/card"]` 53 - 54 - ### `shadcn:get_item_examples_from_registries` 55 - 56 - Find usage examples and demos with source code. 57 - 58 - **Input:** `registries` (string[]), `query` (string) — e.g. `"accordion-demo"`, `"button example"` 59 - 60 - ### `shadcn:get_add_command_for_items` 61 - 62 - Returns the CLI install command. 63 - 64 - **Input:** `items` (string[]) — e.g. `["@shadcn/button"]` 65 - 66 - ### `shadcn:get_audit_checklist` 67 - 68 - Returns a checklist for verifying components (imports, deps, lint, TypeScript). 69 - 70 - **Input:** none 24 + > **Tip:** MCP tools handle registry operations. For project config like aliases, framework, and Tailwind version, use `npx shadcn@latest info`. 71 25 72 - --- 26 + - `shadcn:get_project_registries` - registry names from `components.json` 27 + - `shadcn:list_items_in_registries` - list items in registries 28 + - `shadcn:search_items_in_registries` - fuzzy search 29 + - `shadcn:view_items_in_registries` - view item details and file contents 30 + - `shadcn:get_item_examples_from_registries` - usage examples and demos 31 + - `shadcn:get_add_command_for_items` - install command 32 + - `shadcn:get_audit_checklist` - import, dependency, lint, TypeScript checklist 73 33 74 34 ## Configuring Registries 75 35 76 - Registries are set in `components.json`. The `@shadcn` registry is always built-in. 36 + Registries live in `components.json`. `@shadcn` is built in. 77 37 78 38 ```json 79 39 { ··· 89 49 90 50 - Names must start with `@`. 91 51 - URLs must contain `{name}`. 92 - - `${VAR}` references are resolved from environment variables. 52 + - `${VAR}` comes from environment variables. 93 53 94 54 Community registry index: `https://ui.shadcn.com/r/registries.json`
+11 -250
skills/shadcn/rules/base-vs-radix.md
··· 1 1 # Base vs Radix 2 2 3 - API differences between `base` and `radix`. Check the `base` field from `npx shadcn@latest info`. 3 + Check `base` in `npx shadcn@latest info`. 4 4 5 - ## Contents 5 + ## Key Differences 6 6 7 - - Composition: asChild vs render 8 - - Button / trigger as non-button element 9 - - Select (items prop, placeholder, positioning, multiple, object values) 10 - - ToggleGroup (type vs multiple) 11 - - Slider (scalar vs array) 12 - - Accordion (type and defaultValue) 7 + - Radix uses `asChild`. Base uses `render`. 8 + - Base needs `nativeButton={false}` when `render` changes a button to a non-button element. 9 + - Select differs by `items`, placeholder handling, positioning, and object values. 10 + - ToggleGroup differs by `type` vs `multiple` and by `defaultValue` shape. 11 + - Slider uses a number for single thumb in base. Radix uses an array. 12 + - Accordion uses `multiple` in base. Radix uses `type="single"` or `type="multiple"`. 13 13 14 - --- 15 - 16 - ## Composition: asChild (radix) vs render (base) 17 - 18 - Radix uses `asChild` to replace the default element. Base uses `render`. Don't wrap triggers in extra elements. 19 - 20 - **Incorrect:** 21 - 22 - ```tsx 23 - <DialogTrigger> 24 - <div> 25 - <Button>Open</Button> 26 - </div> 27 - </DialogTrigger> 28 - ``` 29 - 30 - **Correct (radix):** 14 + ## Examples 31 15 32 16 ```tsx 33 17 <DialogTrigger asChild> 34 18 <Button>Open</Button> 35 19 </DialogTrigger> 36 - ``` 37 20 38 - **Correct (base):** 39 - 40 - ```tsx 41 21 <DialogTrigger render={<Button />}>Open</DialogTrigger> 42 22 ``` 43 23 44 - This applies to all trigger and close components: `DialogTrigger`, `SheetTrigger`, `AlertDialogTrigger`, `DropdownMenuTrigger`, `PopoverTrigger`, `TooltipTrigger`, `CollapsibleTrigger`, `DialogClose`, `SheetClose`, `NavigationMenuLink`, `BreadcrumbLink`, `SidebarMenuButton`, `Badge`, `Item`. 45 - 46 - --- 47 - 48 - ## Button / trigger as non-button element (base only) 49 - 50 - When `render` changes an element to a non-button (`<a>`, `<span>`), add `nativeButton={false}`. 51 - 52 - **Incorrect (base):** missing `nativeButton={false}`. 53 - 54 - ```tsx 55 - <Button render={<a href="/docs" />}>Read the docs</Button> 56 - ``` 57 - 58 - **Correct (base):** 59 - 60 24 ```tsx 61 25 <Button render={<a href="/docs" />} nativeButton={false}> 62 26 Read the docs 63 27 </Button> 64 - ``` 65 28 66 - **Correct (radix):** 67 - 68 - ```tsx 69 29 <Button asChild> 70 30 <a href="/docs">Read the docs</a> 71 31 </Button> 72 32 ``` 73 33 74 - Same for triggers whose `render` is not a `Button`: 75 - 76 34 ```tsx 77 - // base. 78 - <PopoverTrigger render={<InputGroupAddon />} nativeButton={false}> 79 - Pick date 80 - </PopoverTrigger> 81 - ``` 82 - 83 - --- 84 - 85 - ## Select 86 - 87 - **items prop (base only).** Base requires an `items` prop on the root. Radix uses inline JSX only. 88 - 89 - **Incorrect (base):** 90 - 91 - ```tsx 92 - <Select> 93 - <SelectTrigger><SelectValue placeholder="Select a fruit" /></SelectTrigger> 94 - </Select> 95 - ``` 96 - 97 - **Correct (base):** 98 - 99 - ```tsx 100 - const items = [ 101 - { label: "Select a fruit", value: null }, 102 - { label: "Apple", value: "apple" }, 103 - { label: "Banana", value: "banana" }, 104 - ] 105 - 106 35 <Select items={items}> 107 - <SelectTrigger> 108 - <SelectValue /> 109 - </SelectTrigger> 110 - <SelectContent> 111 - <SelectGroup> 112 - {items.map((item) => ( 113 - <SelectItem key={item.value} value={item.value}>{item.label}</SelectItem> 114 - ))} 115 - </SelectGroup> 116 - </SelectContent> 36 + <SelectTrigger><SelectValue /></SelectTrigger> 117 37 </Select> 118 - ``` 119 - 120 - **Correct (radix):** 121 38 122 - ```tsx 123 39 <Select> 124 - <SelectTrigger> 125 - <SelectValue placeholder="Select a fruit" /> 126 - </SelectTrigger> 127 - <SelectContent> 128 - <SelectGroup> 129 - <SelectItem value="apple">Apple</SelectItem> 130 - <SelectItem value="banana">Banana</SelectItem> 131 - </SelectGroup> 132 - </SelectContent> 40 + <SelectTrigger><SelectValue placeholder="Select a fruit" /></SelectTrigger> 133 41 </Select> 134 42 ``` 135 43 136 - **Placeholder.** Base uses a `{ value: null }` item in the items array. Radix uses `<SelectValue placeholder="...">`. 137 - 138 - **Content positioning.** Base uses `alignItemWithTrigger`. Radix uses `position`. 139 - 140 44 ```tsx 141 - // base. 142 - <SelectContent alignItemWithTrigger={false} side="bottom"> 143 - 144 - // radix. 145 - <SelectContent position="popper"> 146 - ``` 147 - 148 - --- 149 - 150 - ## Select — multiple selection and object values (base only) 151 - 152 - Base supports `multiple`, render-function children on `SelectValue`, and object values with `itemToStringValue`. Radix is single-select with string values only. 153 - 154 - **Correct (base — multiple selection):** 155 - 156 - ```tsx 157 - <Select items={items} multiple defaultValue={[]}> 158 - <SelectTrigger> 159 - <SelectValue> 160 - {(value: string[]) => value.length === 0 ? "Select fruits" : `${value.length} selected`} 161 - </SelectValue> 162 - </SelectTrigger> 163 - ... 164 - </Select> 165 - ``` 166 - 167 - **Correct (base — object values):** 168 - 169 - ```tsx 170 - <Select defaultValue={plans[0]} itemToStringValue={(plan) => plan.name}> 171 - <SelectTrigger> 172 - <SelectValue>{(value) => value.name}</SelectValue> 173 - </SelectTrigger> 174 - ... 175 - </Select> 176 - ``` 177 - 178 - --- 179 - 180 - ## ToggleGroup 181 - 182 - Base uses a `multiple` boolean prop. Radix uses `type="single"` or `type="multiple"`. 183 - 184 - **Incorrect (base):** 185 - 186 - ```tsx 187 - <ToggleGroup type="single" defaultValue="daily"> 188 - <ToggleGroupItem value="daily">Daily</ToggleGroupItem> 189 - </ToggleGroup> 190 - ``` 191 - 192 - **Correct (base):** 193 - 194 - ```tsx 195 - // Single (no prop needed), defaultValue is always an array. 196 45 <ToggleGroup defaultValue={["daily"]} spacing={2}> 197 46 <ToggleGroupItem value="daily">Daily</ToggleGroupItem> 198 - <ToggleGroupItem value="weekly">Weekly</ToggleGroupItem> 199 47 </ToggleGroup> 200 48 201 - // Multi-selection. 202 - <ToggleGroup multiple> 203 - <ToggleGroupItem value="bold">Bold</ToggleGroupItem> 204 - <ToggleGroupItem value="italic">Italic</ToggleGroupItem> 205 - </ToggleGroup> 206 - ``` 207 - 208 - **Correct (radix):** 209 - 210 - ```tsx 211 - // Single, defaultValue is a string. 212 49 <ToggleGroup type="single" defaultValue="daily" spacing={2}> 213 50 <ToggleGroupItem value="daily">Daily</ToggleGroupItem> 214 - <ToggleGroupItem value="weekly">Weekly</ToggleGroupItem> 215 - </ToggleGroup> 216 - 217 - // Multi-selection. 218 - <ToggleGroup type="multiple"> 219 - <ToggleGroupItem value="bold">Bold</ToggleGroupItem> 220 - <ToggleGroupItem value="italic">Italic</ToggleGroupItem> 221 51 </ToggleGroup> 222 52 ``` 223 53 224 - **Controlled single value:** 225 - 226 - ```tsx 227 - // base — wrap/unwrap arrays. 228 - const [value, setValue] = React.useState("normal") 229 - <ToggleGroup value={[value]} onValueChange={(v) => setValue(v[0])}> 230 - 231 - // radix — plain string. 232 - const [value, setValue] = React.useState("normal") 233 - <ToggleGroup type="single" value={value} onValueChange={setValue}> 234 - ``` 235 - 236 - --- 237 - 238 - ## Slider 239 - 240 - Base accepts a plain number for a single thumb. Radix always requires an array. 241 - 242 - **Incorrect (base):** 243 - 244 - ```tsx 245 - <Slider defaultValue={[50]} max={100} step={1} /> 246 - ``` 247 - 248 - **Correct (base):** 249 - 250 54 ```tsx 251 55 <Slider defaultValue={50} max={100} step={1} /> 252 - ``` 253 - 254 - **Correct (radix):** 255 - 256 - ```tsx 257 56 <Slider defaultValue={[50]} max={100} step={1} /> 258 57 ``` 259 - 260 - Both use arrays for range sliders. Controlled `onValueChange` in base may need a cast: 261 - 262 - ```tsx 263 - // base. 264 - const [value, setValue] = React.useState([0.3, 0.7]) 265 - <Slider value={value} onValueChange={(v) => setValue(v as number[])} /> 266 - 267 - // radix. 268 - const [value, setValue] = React.useState([0.3, 0.7]) 269 - <Slider value={value} onValueChange={setValue} /> 270 - ``` 271 - 272 - --- 273 - 274 - ## Accordion 275 - 276 - 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. 277 - 278 - **Incorrect (base):** 279 - 280 - ```tsx 281 - <Accordion type="single" collapsible defaultValue="item-1"> 282 - <AccordionItem value="item-1">...</AccordionItem> 283 - </Accordion> 284 - ``` 285 - 286 - **Correct (base):** 287 58 288 59 ```tsx 289 60 <Accordion defaultValue={["item-1"]}> 290 61 <AccordionItem value="item-1">...</AccordionItem> 291 62 </Accordion> 292 63 293 - // Multi-select. 294 - <Accordion multiple defaultValue={["item-1", "item-2"]}> 295 - <AccordionItem value="item-1">...</AccordionItem> 296 - <AccordionItem value="item-2">...</AccordionItem> 297 - </Accordion> 298 - ``` 299 - 300 - **Correct (radix):** 301 - 302 - ```tsx 303 64 <Accordion type="single" collapsible defaultValue="item-1"> 304 65 <AccordionItem value="item-1">...</AccordionItem> 305 66 </Accordion>
+17 -125
skills/shadcn/rules/composition.md
··· 1 1 # Component Composition 2 2 3 - ## Contents 4 - 5 - - Items always inside their Group component 6 - - Callouts use Alert 7 - - Empty states use Empty component 8 - - Toast notifications use sonner 9 - - Choosing between overlay components 10 - - Dialog, Sheet, and Drawer always need a Title 11 - - Card structure 12 - - Button has no isPending or isLoading prop 13 - - TabsTrigger must be inside TabsList 14 - - Avatar always needs AvatarFallback 15 - - Use Separator instead of raw hr or border divs 16 - - Use Skeleton for loading placeholders 17 - - Use Badge instead of custom styled spans 18 - 19 - --- 20 - 21 - ## Items always inside their Group component 3 + ## Rules 22 4 23 - Never render items directly inside the content container. 5 + - Items stay inside their group component. 6 + - Use `Alert` for callouts. 7 + - Use `Empty` for empty states. 8 + - Use `sonner` for toasts. 9 + - Use `Dialog`, `Sheet`, `Drawer`, `HoverCard`, or `Popover` by intent. 10 + - `Dialog`, `Sheet`, and `Drawer` always need a title. 11 + - Use full `Card` composition. 12 + - `Button` has no `isPending` or `isLoading` prop. 13 + - `TabsTrigger` must stay inside `TabsList`. 14 + - `Avatar` needs `AvatarFallback`. 15 + - Use `Separator` instead of raw `<hr>` or border divs. 16 + - Use `Skeleton` for loading placeholders. 17 + - Use `Badge` instead of custom spans. 24 18 25 - **Incorrect:** 26 - 27 - ```tsx 28 - <SelectContent> 29 - <SelectItem value="apple">Apple</SelectItem> 30 - <SelectItem value="banana">Banana</SelectItem> 31 - </SelectContent> 32 - ``` 33 - 34 - **Correct:** 19 + ## Examples 35 20 36 21 ```tsx 37 22 <SelectContent> ··· 42 27 </SelectContent> 43 28 ``` 44 29 45 - This applies to all group-based components: 46 - 47 - | Item | Group | 48 - |------|-------| 49 - | `SelectItem`, `SelectLabel` | `SelectGroup` | 50 - | `DropdownMenuItem`, `DropdownMenuLabel`, `DropdownMenuSub` | `DropdownMenuGroup` | 51 - | `MenubarItem` | `MenubarGroup` | 52 - | `ContextMenuItem` | `ContextMenuGroup` | 53 - | `CommandItem` | `CommandGroup` | 54 - 55 - --- 56 - 57 - ## Callouts use Alert 58 - 59 30 ```tsx 60 31 <Alert> 61 32 <AlertTitle>Warning</AlertTitle> 62 33 <AlertDescription>Something needs attention.</AlertDescription> 63 34 </Alert> 64 35 ``` 65 - 66 - --- 67 - 68 - ## Empty states use Empty component 69 36 70 37 ```tsx 71 38 <Empty> ··· 74 41 <EmptyTitle>No projects yet</EmptyTitle> 75 42 <EmptyDescription>Get started by creating a new project.</EmptyDescription> 76 43 </EmptyHeader> 77 - <EmptyContent> 78 - <Button>Create Project</Button> 79 - </EmptyContent> 44 + <EmptyContent><Button>Create Project</Button></EmptyContent> 80 45 </Empty> 81 46 ``` 82 - 83 - --- 84 - 85 - ## Toast notifications use sonner 86 47 87 48 ```tsx 88 49 import { toast } from "sonner" 89 50 90 51 toast.success("Changes saved.") 91 52 toast.error("Something went wrong.") 92 - toast("File deleted.", { 93 - action: { label: "Undo", onClick: () => undoDelete() }, 94 - }) 95 53 ``` 96 54 97 - --- 98 - 99 - ## Choosing between overlay components 100 - 101 - | Use case | Component | 102 - |----------|-----------| 103 - | Focused task that requires input | `Dialog` | 104 - | Destructive action confirmation | `AlertDialog` | 105 - | Side panel with details or filters | `Sheet` | 106 - | Mobile-first bottom panel | `Drawer` | 107 - | Quick info on hover | `HoverCard` | 108 - | Small contextual content on click | `Popover` | 109 - 110 - --- 111 - 112 - ## Dialog, Sheet, and Drawer always need a Title 113 - 114 - `DialogTitle`, `SheetTitle`, `DrawerTitle` are required for accessibility. Use `className="sr-only"` if visually hidden. 115 - 116 - ```tsx 117 - <DialogContent> 118 - <DialogHeader> 119 - <DialogTitle>Edit Profile</DialogTitle> 120 - <DialogDescription>Update your profile.</DialogDescription> 121 - </DialogHeader> 122 - ... 123 - </DialogContent> 124 - ``` 125 - 126 - --- 127 - 128 - ## Card structure 129 - 130 - Use full composition — don't dump everything into `CardContent`: 131 - 132 55 ```tsx 133 56 <Card> 134 57 <CardHeader> ··· 136 59 <CardDescription>Manage your team.</CardDescription> 137 60 </CardHeader> 138 61 <CardContent>...</CardContent> 139 - <CardFooter> 140 - <Button>Invite</Button> 141 - </CardFooter> 62 + <CardFooter><Button>Invite</Button></CardFooter> 142 63 </Card> 143 64 ``` 144 65 145 - --- 146 - 147 - ## Button has no isPending or isLoading prop 148 - 149 - Compose with `Spinner` + `data-icon` + `disabled`: 150 - 151 66 ```tsx 152 67 <Button disabled> 153 68 <Spinner data-icon="inline-start" /> 154 69 Saving... 155 70 </Button> 156 71 ``` 157 - 158 - --- 159 - 160 - ## TabsTrigger must be inside TabsList 161 - 162 - Never render `TabsTrigger` directly inside `Tabs` — always wrap in `TabsList`: 163 72 164 73 ```tsx 165 74 <Tabs defaultValue="account"> 166 75 <TabsList> 167 76 <TabsTrigger value="account">Account</TabsTrigger> 168 - <TabsTrigger value="password">Password</TabsTrigger> 169 77 </TabsList> 170 78 <TabsContent value="account">...</TabsContent> 171 79 </Tabs> 172 80 ``` 173 81 174 - --- 175 - 176 - ## Avatar always needs AvatarFallback 177 - 178 - Always include `AvatarFallback` for when the image fails to load: 179 - 180 82 ```tsx 181 83 <Avatar> 182 84 <AvatarImage src="/avatar.png" alt="User" /> 183 85 <AvatarFallback>JD</AvatarFallback> 184 86 </Avatar> 185 87 ``` 186 - 187 - --- 188 - 189 - ## Use existing components instead of custom markup 190 - 191 - | Instead of | Use | 192 - |---|---| 193 - | `<hr>` or `<div className="border-t">` | `<Separator />` | 194 - | `<div className="animate-pulse">` with styled divs | `<Skeleton className="h-4 w-3/4" />` | 195 - | `<span className="rounded-full bg-green-100 ...">` | `<Badge variant="secondary">` |
+15 -134
skills/shadcn/rules/forms.md
··· 1 1 # Forms & Inputs 2 2 3 - ## Contents 3 + ## Rules 4 4 5 - - Forms use FieldGroup + Field 6 - - InputGroup requires InputGroupInput/InputGroupTextarea 7 - - Buttons inside inputs use InputGroup + InputGroupAddon 8 - - Option sets (2–7 choices) use ToggleGroup 9 - - FieldSet + FieldLegend for grouping related fields 10 - - Field validation and disabled states 5 + - Use `FieldGroup` + `Field` for forms. 6 + - Use `InputGroupInput` and `InputGroupTextarea` inside `InputGroup`. 7 + - Use `InputGroup` + `InputGroupAddon` for buttons inside inputs. 8 + - Use `ToggleGroup` for 2 to 7 options. 9 + - Use `FieldSet` + `FieldLegend` for grouped checkboxes or radios. 10 + - Use `data-invalid` and `data-disabled` on the field. Use `aria-invalid` or `disabled` on the control. 11 11 12 - --- 13 - 14 - ## Forms use FieldGroup + Field 15 - 16 - Always use `FieldGroup` + `Field` — never raw `div` with `space-y-*`: 12 + ## Examples 17 13 18 14 ```tsx 19 15 <FieldGroup> 20 16 <Field> 21 17 <FieldLabel htmlFor="email">Email</FieldLabel> 22 18 <Input id="email" type="email" /> 23 - </Field> 24 - <Field> 25 - <FieldLabel htmlFor="password">Password</FieldLabel> 26 - <Input id="password" type="password" /> 27 19 </Field> 28 20 </FieldGroup> 29 21 ``` 30 22 31 - Use `Field orientation="horizontal"` for settings pages. Use `FieldLabel className="sr-only"` for visually hidden labels. 32 - 33 - **Choosing form controls:** 34 - 35 - - Simple text input → `Input` 36 - - Dropdown with predefined options → `Select` 37 - - Searchable dropdown → `Combobox` 38 - - Native HTML select (no JS) → `native-select` 39 - - Boolean toggle → `Switch` (for settings) or `Checkbox` (for forms) 40 - - Single choice from few options → `RadioGroup` 41 - - Toggle between 2–5 options → `ToggleGroup` + `ToggleGroupItem` 42 - - OTP/verification code → `InputOTP` 43 - - Multi-line text → `Textarea` 44 - 45 - --- 46 - 47 - ## InputGroup requires InputGroupInput/InputGroupTextarea 48 - 49 - Never use raw `Input` or `Textarea` inside an `InputGroup`. 50 - 51 - **Incorrect:** 52 - 53 23 ```tsx 54 - <InputGroup> 55 - <Input placeholder="Search..." /> 56 - </InputGroup> 24 + <Field orientation="horizontal"> 25 + <FieldLabel className="sr-only">Search</FieldLabel> 26 + <InputGroup> 27 + <InputGroupInput placeholder="Search..." /> 28 + </InputGroup> 29 + </Field> 57 30 ``` 58 - 59 - **Correct:** 60 31 61 32 ```tsx 62 - import { InputGroup, InputGroupInput } from "@/components/ui/input-group" 63 - 64 - <InputGroup> 65 - <InputGroupInput placeholder="Search..." /> 66 - </InputGroup> 67 - ``` 68 - 69 - --- 70 - 71 - ## Buttons inside inputs use InputGroup + InputGroupAddon 72 - 73 - Never place a `Button` directly inside or adjacent to an `Input` with custom positioning. 74 - 75 - **Incorrect:** 76 - 77 - ```tsx 78 - <div className="relative"> 79 - <Input placeholder="Search..." className="pr-10" /> 80 - <Button className="absolute right-0 top-0" size="icon"> 81 - <SearchIcon /> 82 - </Button> 83 - </div> 84 - ``` 85 - 86 - **Correct:** 87 - 88 - ```tsx 89 - import { InputGroup, InputGroupInput, InputGroupAddon } from "@/components/ui/input-group" 90 - 91 33 <InputGroup> 92 34 <InputGroupInput placeholder="Search..." /> 93 35 <InputGroupAddon> ··· 97 39 </InputGroupAddon> 98 40 </InputGroup> 99 41 ``` 100 - 101 - --- 102 - 103 - ## Option sets (2–7 choices) use ToggleGroup 104 - 105 - Don't manually loop `Button` components with active state. 106 - 107 - **Incorrect:** 108 - 109 - ```tsx 110 - const [selected, setSelected] = useState("daily") 111 - 112 - <div className="flex gap-2"> 113 - {["daily", "weekly", "monthly"].map((option) => ( 114 - <Button 115 - key={option} 116 - variant={selected === option ? "default" : "outline"} 117 - onClick={() => setSelected(option)} 118 - > 119 - {option} 120 - </Button> 121 - ))} 122 - </div> 123 - ``` 124 - 125 - **Correct:** 126 42 127 43 ```tsx 128 - import { ToggleGroup, ToggleGroupItem } from "@/components/ui/toggle-group" 129 - 130 - <ToggleGroup spacing={2}> 44 + <ToggleGroup defaultValue={["daily"]} spacing={2}> 131 45 <ToggleGroupItem value="daily">Daily</ToggleGroupItem> 132 46 <ToggleGroupItem value="weekly">Weekly</ToggleGroupItem> 133 - <ToggleGroupItem value="monthly">Monthly</ToggleGroupItem> 134 47 </ToggleGroup> 135 48 ``` 136 49 137 - Combine with `Field` for labelled toggle groups: 138 - 139 - ```tsx 140 - <Field orientation="horizontal"> 141 - <FieldTitle id="theme-label">Theme</FieldTitle> 142 - <ToggleGroup aria-labelledby="theme-label" spacing={2}> 143 - <ToggleGroupItem value="light">Light</ToggleGroupItem> 144 - <ToggleGroupItem value="dark">Dark</ToggleGroupItem> 145 - <ToggleGroupItem value="system">System</ToggleGroupItem> 146 - </ToggleGroup> 147 - </Field> 148 - ``` 149 - 150 - > **Note:** `defaultValue` and `type`/`multiple` props differ between base and radix. See [base-vs-radix.md](./base-vs-radix.md#togglegroup). 151 - 152 - --- 153 - 154 - ## FieldSet + FieldLegend for grouping related fields 155 - 156 - Use `FieldSet` + `FieldLegend` for related checkboxes, radios, or switches — not `div` with a heading: 157 - 158 50 ```tsx 159 51 <FieldSet> 160 52 <FieldLegend variant="label">Preferences</FieldLegend> 161 - <FieldDescription>Select all that apply.</FieldDescription> 162 53 <FieldGroup className="gap-3"> 163 54 <Field orientation="horizontal"> 164 55 <Checkbox id="dark" /> ··· 168 59 </FieldSet> 169 60 ``` 170 61 171 - --- 172 - 173 - ## Field validation and disabled states 174 - 175 - Both attributes are needed — `data-invalid`/`data-disabled` styles the field (label, description), while `aria-invalid`/`disabled` styles the control. 176 - 177 62 ```tsx 178 - // Invalid. 179 63 <Field data-invalid> 180 64 <FieldLabel htmlFor="email">Email</FieldLabel> 181 65 <Input id="email" aria-invalid /> 182 66 <FieldDescription>Invalid email address.</FieldDescription> 183 67 </Field> 184 68 185 - // Disabled. 186 69 <Field data-disabled> 187 70 <FieldLabel htmlFor="email">Email</FieldLabel> 188 71 <Input id="email" disabled /> 189 72 </Field> 190 73 ``` 191 - 192 - Works for all controls: `Input`, `Textarea`, `Select`, `Checkbox`, `RadioGroupItem`, `Switch`, `Slider`, `NativeSelect`, `InputOTP`.
+8 -64
skills/shadcn/rules/icons.md
··· 1 1 # Icons 2 2 3 - **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`. 3 + Use the project's configured `iconLibrary` for imports. Do not assume `lucide-react`. 4 4 5 - --- 6 - 7 - ## Icons in Button use data-icon attribute 8 - 9 - Add `data-icon="inline-start"` (prefix) or `data-icon="inline-end"` (suffix) to the icon. No sizing classes on the icon. 10 - 11 - **Incorrect:** 5 + ## Rules 12 6 13 - ```tsx 14 - <Button> 15 - <SearchIcon className="mr-2 size-4" /> 16 - Search 17 - </Button> 18 - ``` 7 + - Icons in `Button` use `data-icon="inline-start"` or `data-icon="inline-end"`. 8 + - Do not size icons inside shadcn components unless the user asks for custom sizes. 9 + - Pass icons as component objects, not string keys. 19 10 20 - **Correct:** 11 + ## Examples 21 12 22 13 ```tsx 23 14 <Button> 24 - <SearchIcon data-icon="inline-start"/> 15 + <SearchIcon data-icon="inline-start" /> 25 16 Search 26 17 </Button> 27 18 28 19 <Button> 29 20 Next 30 - <ArrowRightIcon data-icon="inline-end"/> 31 - </Button> 32 - ``` 33 - 34 - --- 35 - 36 - ## No sizing classes on icons inside components 37 - 38 - 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. 39 - 40 - **Incorrect:** 41 - 42 - ```tsx 43 - <Button> 44 - <SearchIcon className="size-4" data-icon="inline-start" /> 45 - Search 21 + <ArrowRightIcon data-icon="inline-end" /> 46 22 </Button> 47 - 48 - <DropdownMenuItem> 49 - <SettingsIcon className="mr-2 size-4" /> 50 - Settings 51 - </DropdownMenuItem> 52 23 ``` 53 24 54 - **Correct:** 55 - 56 25 ```tsx 57 26 <Button> 58 27 <SearchIcon data-icon="inline-start" /> ··· 65 34 </DropdownMenuItem> 66 35 ``` 67 36 68 - --- 69 - 70 - ## Pass icons as component objects, not string keys 71 - 72 - Use `icon={CheckIcon}`, not a string key to a lookup map. 73 - 74 - **Incorrect:** 75 - 76 37 ```tsx 77 - const iconMap = { 78 - check: CheckIcon, 79 - alert: AlertIcon, 80 - } 81 - 82 - function StatusBadge({ icon }: { icon: string }) { 83 - const Icon = iconMap[icon] 84 - return <Icon /> 85 - } 86 - 87 - <StatusBadge icon="check" /> 88 - ``` 89 - 90 - **Correct:** 91 - 92 - ```tsx 93 - // Import from the project's configured iconLibrary (e.g. lucide-react, @tabler/icons-react). 94 38 import { CheckIcon } from "lucide-react" 95 39 96 40 function StatusBadge({ icon: Icon }: { icon: React.ComponentType }) {
+15 -122
skills/shadcn/rules/styling.md
··· 1 1 # Styling & Customization 2 2 3 - See [customization.md](../customization.md) for theming, CSS variables, and adding custom colors. 3 + See [customization.md](../customization.md) for theming, CSS variables, and custom colors. 4 4 5 - ## Contents 5 + ## Core Rules 6 6 7 - - Semantic colors 8 - - Built-in variants first 9 - - className for layout only 10 - - No space-x-* / space-y-* 11 - - Prefer size-* over w-* h-* when equal 12 - - Prefer truncate shorthand 13 - - No manual dark: color overrides 14 - - Use cn() for conditional classes 15 - - No manual z-index on overlay components 7 + - Use semantic colors. Prefer `bg-primary` and `text-muted-foreground` over raw color values. 8 + - Use built-in variants first. 9 + - Use `className` for layout only, not to override component styling. 10 + - Avoid `space-x-*` and `space-y-*`. Use `gap-*`. 11 + - Use `size-*` when width and height match. 12 + - Use `truncate` instead of the long overflow combo. 13 + - Do not add manual `dark:` overrides. Use semantic tokens. 14 + - Use `cn()` for conditional classes. 15 + - Do not set `z-index` manually on overlay components. 16 16 17 - --- 18 - 19 - ## Semantic colors 20 - 21 - **Incorrect:** 22 - 23 - ```tsx 24 - <div className="bg-blue-500 text-white"> 25 - <p className="text-gray-600">Secondary text</p> 26 - </div> 27 - ``` 28 - 29 - **Correct:** 17 + ## Examples 30 18 31 19 ```tsx 32 20 <div className="bg-primary text-primary-foreground"> 33 21 <p className="text-muted-foreground">Secondary text</p> 34 22 </div> 35 23 ``` 36 - 37 - --- 38 - 39 - ## No raw color values for status/state indicators 40 - 41 - 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. 42 - 43 - **Incorrect:** 44 - 45 - ```tsx 46 - <span className="text-emerald-600">+20.1%</span> 47 - <span className="text-green-500">Active</span> 48 - <span className="text-red-600">-3.2%</span> 49 - ``` 50 - 51 - **Correct:** 52 24 53 25 ```tsx 54 26 <Badge variant="secondary">+20.1%</Badge> 55 - <Badge>Active</Badge> 56 27 <span className="text-destructive">-3.2%</span> 57 28 ``` 58 - 59 - 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)). 60 - 61 - --- 62 - 63 - ## Built-in variants first 64 - 65 - **Incorrect:** 66 - 67 - ```tsx 68 - <Button className="border border-input bg-transparent hover:bg-accent"> 69 - Click me 70 - </Button> 71 - ``` 72 - 73 - **Correct:** 74 29 75 30 ```tsx 76 31 <Button variant="outline">Click me</Button> 77 - ``` 78 - 79 - --- 80 - 81 - ## className for layout only 82 - 83 - 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. 84 - 85 - **Incorrect:** 86 - 87 - ```tsx 88 - <Card className="bg-blue-100 text-blue-900 font-bold"> 89 - <CardContent>Dashboard</CardContent> 90 - </Card> 91 - ``` 92 - 93 - **Correct:** 94 - 95 - ```tsx 96 32 <Card className="max-w-md mx-auto"> 97 33 <CardContent>Dashboard</CardContent> 98 34 </Card> 99 35 ``` 100 36 101 - To customize a component's appearance, prefer these approaches in order: 102 - 1. **Built-in variants** — `variant="outline"`, `variant="destructive"`, etc. 103 - 2. **Semantic color tokens** — `bg-primary`, `text-muted-foreground`. 104 - 3. **CSS variables** — define custom colors in the global CSS file (see [customization.md](../customization.md)). 105 - 106 - --- 107 - 108 - ## No space-x-* / space-y-* 109 - 110 - Use `gap-*` instead. `space-y-4` → `flex flex-col gap-4`. `space-x-2` → `flex gap-2`. 111 - 112 37 ```tsx 113 38 <div className="flex flex-col gap-4"> 114 39 <Input /> ··· 117 42 </div> 118 43 ``` 119 44 120 - --- 121 - 122 - ## Prefer size-* over w-* h-* when equal 123 - 124 - `size-10` not `w-10 h-10`. Applies to icons, avatars, skeletons, etc. 125 - 126 - --- 127 - 128 - ## Prefer truncate shorthand 129 - 130 - `truncate` not `overflow-hidden text-ellipsis whitespace-nowrap`. 131 - 132 - --- 133 - 134 - ## No manual dark: color overrides 135 - 136 - Use semantic tokens — they handle light/dark via CSS variables. `bg-background text-foreground` not `bg-white dark:bg-gray-950`. 137 - 138 - --- 139 - 140 - ## Use cn() for conditional classes 141 - 142 - Use the `cn()` utility from the project for conditional or merged class names. Don't write manual ternaries in className strings. 143 - 144 - **Incorrect:** 145 - 146 45 ```tsx 147 - <div className={`flex items-center ${isActive ? "bg-primary text-primary-foreground" : "bg-muted"}`}> 46 + <Avatar className="size-10" /> 148 47 ``` 149 - 150 - **Correct:** 151 48 152 49 ```tsx 153 - import { cn } from "@/lib/utils" 154 - 155 50 <div className={cn("flex items-center", isActive ? "bg-primary text-primary-foreground" : "bg-muted")}> 156 51 ``` 157 52 158 - --- 159 - 160 - ## No manual z-index on overlay components 53 + ## Overlay Rules 161 54 162 - `Dialog`, `Sheet`, `Drawer`, `AlertDialog`, `DropdownMenu`, `Popover`, `Tooltip`, `HoverCard` handle their own stacking. Never add `z-50` or `z-[999]`. 55 + `Dialog`, `Sheet`, `Drawer`, `AlertDialog`, `DropdownMenu`, `Popover`, `Tooltip`, and `HoverCard` manage stacking. Do not add `z-50` or similar.