shadcn/ui
Pathrule2 Rules • 3 Memories • 1 Skill
shadcn/ui is a code distribution system that copies accessible, Tailwind-styled React components straight into your repo via a CLI and registries, so you own and edit every line. This pattern keeps your team aligned on theming through CSS variables, safe component composition, and the CLI and registry workflow. It encodes the current 2026 conventions: Tailwind v4, the unified Radix UI package, namespaced registries, and the shadcn MCP server.
Suggested path map
Pathrule places each piece on the matching path, so your assistant only sees it where it belongs. This is the scoping you get on import; you can adjust it in your workspace.
Rules
2Treat /components/ui as registry-owned, composable code/src/components/uihighstrictAdd and update primitives through the shadcn CLI; compose around them instead of forking or hand-editing them.
| 1 | Files under `components/ui` are owned by the shadcn registry workflow, not authored or rewritten by hand. |
| 2 | |
| 3 | - Add or update a primitive with `npx shadcn@latest add <component>` so registry dependencies, imports, and metadata stay correct. Do not write a primitive from scratch. |
| 4 | - Before re-running `add` on an already-installed primitive, preview with `--dry-run` (shows what the registry will write) and `--diff` (compares against your local changes) so customizations are not silently overwritten. |
| 5 | - When you need new behavior, build a feature component in `components/` that imports and wraps the primitive. Do not fork the primitive in place. Forked primitives drift from upstream a11y and security fixes and break future `add`/`migrate` runs. |
| 6 | - Route every class merge through the `cn` helper in `lib/utils` (`clsx` + `tailwind-merge`). Concatenating class strings by hand defeats `tailwind-merge` conflict resolution and makes variant overrides resolve unpredictably. |
| 7 | - Do not strip Radix primitive props, `aria-*` attributes, `data-*` state hooks, or focus/keyboard handlers when wrapping. Those carry the accessibility contract. |
Theme only through semantic CSS-variable tokens/src/apphighstrictStyle with token classes like bg-background and text-primary; never raw hex, arbitrary values, or palette classes.
| 1 | shadcn/ui themes via semantic CSS variables defined in your global stylesheet. Every color must flow through them. |
| 2 | |
| 3 | - Use semantic utility classes (`bg-background`, `text-foreground`, `border-border`, `bg-primary`, `text-primary-foreground`, `text-muted-foreground`) instead of `bg-white`, `text-zinc-900`, `bg-[#fff]`, or arbitrary `dark:bg-[#...]` values. |
| 4 | - Adjust the palette by editing the `--background`, `--foreground`, `--primary`, `--muted`, `--border`, and related variables in your global CSS, not by sprinkling colors across components. |
| 5 | - Keep the `:root` and `.dark` blocks in sync so dark mode resolves from the same token names. A token defined in `:root` but missing in `.dark` (or vice versa) is the most common cause of broken dark mode. |
| 6 | - With Tailwind v4, leave `tailwind.config` blank in `components.json` and rely on the CSS-first `@import`/`@theme` setup. Reintroducing a JS theme config alongside v4 CSS tokens produces two competing sources of truth. |
| 7 | - Keep `cssVariables: true` in `components.json`. Setting it to `false` switches to utility-class theming and silently breaks the semantic-token model the rest of the codebase assumes. |
Memories
3How shadcn/ui actually works in this repo/rootComponents are copied into our codebase via the CLI and registries; nothing is imported from a UI runtime package.
| 1 | shadcn/ui is a code-distribution system, not a component dependency. The source of truth for every component lives in our own files. |
| 2 | |
| 3 | - Running the CLI copies component source into `components/ui` and resolves aliases from `components.json` (`components`, `ui`, `lib`, `utils`, `hooks`). There is no `@shadcn/ui` runtime import and no such package to add to `package.json`. |
| 4 | - As of 2026 the `new-york` style imports primitives from the unified `radix-ui` package (single import surface, e.g. `import { Dialog as DialogPrimitive } from "radix-ui"`) instead of many `@radix-ui/react-*` packages. The legacy default style is deprecated; use `new-york`. |
| 5 | - Variants are built with `class-variance-authority`; the `baseColor` in `components.json` (`neutral`, `stone`, `zinc`, `mauve`, `olive`, `mist`, `taupe`) seeds the token palette, and `cssVariables: true` is what enables semantic-token theming. |
| 6 | - The three pillars: edit CSS-variable tokens to change theme, compose feature components around primitives, and re-run the CLI to pull upstream fixes. Treat `cn`, the token set, and registry-managed primitives as immutable plumbing. |
| 7 | |
| 8 | See also: `/src/components` for the CLI v4 + registry + MCP workflow, and `/src/app` for the Tailwind v4 CSS-first theming setup. |
CLI v4 workflow, namespaced registries, and the MCP server/src/componentsUse the v4 CLI commands, namespaced registries, and the shadcn MCP server to add, inspect, and discover components.
| 1 | The shadcn CLI v4 (2026) plus registries are how we install and extend UI. Learn the workflow before adding components. |
| 2 | |
| 3 | - Core commands: `init` (scaffolds and writes `components.json`; supports `--template`, `--base` to pick Radix or Base UI, `--monorepo`), `add`, `search`, `view`, `build`, plus `info` (prints framework, Tailwind version, CSS-vars setting, aliases, and installed components) and `docs` (returns component docs, examples, and API directly from the CLI). |
| 4 | - `info --json` is the canonical way to read this project's resolved config; prefer it over guessing paths or framework. The shadcn skill activates off the presence of `components.json`. |
| 5 | - Namespaced registries install with `@namespace/name` syntax. Declare them in `components.json` under `registries`, e.g. `"@acme": "https://registry.acme.com/{name}.json"`; `{name}` is replaced at install time. For private registries, add `headers` with `${ENV_VAR}` expansion (e.g. `"Authorization": "Bearer ${REGISTRY_TOKEN}"`) and never commit the token. |
| 6 | - Registries can ship whole design systems in one payload via `registry:base` (components + deps + CSS vars + fonts + config), and fonts are first-class via `registry:font`. Pin private/pro registry URLs to a tag or digest so installs are reproducible; use kebab-case item names with accurate `registryDependencies`. |
| 7 | - The shadcn MCP server (`npx shadcn@latest mcp init --client claude`) reads `components.json` and lets an agent search, preview (`view`), and add components across configured registries from natural language. Manual config lives in `.mcp.json` (Claude Code), `.cursor/mcp.json`, or `.vscode/mcp.json`. |
Tailwind v4 CSS-first setup is the main shadcn footgun/src/appglobals.css drives everything in v4: tw-animate-css, @custom-variant dark, @theme inline, and hsl()-wrapped tokens.
| 1 | Tailwind v4 moved theming into CSS, and most shadcn breakage comes from getting `globals.css` wrong. The current setup: |
| 2 | |
| 3 | - `@import "tailwindcss";` then `@import "tw-animate-css";`. `tailwindcss-animate` (the v3 PostCSS plugin) is deprecated and replaced by `tw-animate-css`; new shadcn projects install it by default. If animations/transitions silently stop working, this import is usually missing or still pointing at the old plugin. |
| 4 | - Dark mode is enabled with `@custom-variant dark (&:is(.dark *));` in `globals.css`, not via `darkMode` in a JS config. Without this line `dark:` variants resolve to nothing. |
| 5 | - Map CSS variables to Tailwind tokens with `@theme inline { ... }` so utilities like `bg-background` exist. Color values are wrapped in `hsl()` (e.g. `--background: hsl(...)`) and referenced through the `@theme inline` block. |
| 6 | - `tailwind.config` stays blank in `components.json`; there is no `tailwind.config.js`/`.ts` to edit for theme in v4. Do not recreate one to "fix" tokens, set them in CSS. |
| 7 | - Define every token in both `:root` and `.dark`. A token present in one block but not the other is the top cause of half-broken dark mode. |
| 8 | - When migrating an existing project's primitives to the unified Radix package, run `npx shadcn@latest migrate radix` (append a path like `src/components/custom` for non-standard directories) rather than rewriting imports by hand. |
Skills
1shadcn-ui-review/rootPre-merge checklist for shadcn/ui changes: distribution model, theming, composition, CLI/registry usage, and a11y.
| 1 | --- |
| 2 | name: shadcn-ui-review |
| 3 | description: Review a shadcn/ui change before merge. Verifies the code-distribution model, CSS-variable theming, composition over forking, correct CLI v4 and registry usage, Tailwind v4 setup, and accessibility. Use when adding or editing components under components/ui or any UI built on shadcn primitives. |
| 4 | --- |
| 5 | |
| 6 | # shadcn/ui review |
| 7 | |
| 8 | ## Distribution model |
| 9 | - [ ] No `@shadcn/ui` or external UI-library runtime import; primitives live in `components/ui` and were added via `npx shadcn@latest add`. |
| 10 | - [ ] `new-york` style; primitives import from the unified `radix-ui` package, not legacy `@radix-ui/react-*` (run `migrate radix` if mixed). |
| 11 | |
| 12 | ## Theming |
| 13 | - [ ] Colors use semantic tokens (`bg-background`, `text-foreground`, `bg-primary`) with no hex, arbitrary `[#...]`, or raw palette classes. |
| 14 | - [ ] Theme edits were made in CSS variables, with every token present in BOTH `:root` and `.dark`. |
| 15 | - [ ] Tailwind v4: `globals.css` has `@import "tw-animate-css"`, `@custom-variant dark (&:is(.dark *))`, and `@theme inline` token mapping; `tailwind.config` blank in `components.json`; `cssVariables: true`. |
| 16 | |
| 17 | ## Composition |
| 18 | - [ ] New behavior is composed in `components/` around primitives, not by forking the generated primitive in place. |
| 19 | - [ ] Class merging goes through the `cn` helper so `tailwind-merge` resolves conflicting variants. |
| 20 | |
| 21 | ## CLI & registries |
| 22 | - [ ] Re-runs of `add` were previewed with `--dry-run`/`--diff` so local customizations were not overwritten. |
| 23 | - [ ] Registry installs use correct `@namespace/name`; private registries authenticate via `${ENV_VAR}` headers (no committed tokens) and pin a tag/digest. |
| 24 | |
| 25 | ## Accessibility |
| 26 | - [ ] Radix props, `aria-*`, `data-*` state, focus styles, and keyboard interaction are intact. |
| 27 | - [ ] Both color schemes verified visually for the changed components. |
Why this pattern
AI agents treat shadcn/ui like an npm package, hand-editing generated primitives and hardcoding colors instead of theming through CSS variables.
Built for React and Next.js teams using shadcn/ui with Tailwind v4.
Keeps your assistant from:
- Importing shadcn/ui as a runtime dependency instead of copying components into the repo
- Hardcoding hex colors or Tailwind palette classes instead of using semantic CSS-variable tokens
- Forking generated primitives by editing them in place instead of composing new components around them
- License
- Apache-2.0
- Version
- 1.0.0
- Updated
- 2026-06-09