shadcn
Project-aware shadcn/ui workflow for searching, adding, composing, and fixing components with correct patterns.
Install
npx skills add https://github.com/shadcn-ui/ui --skill shadcnDesign Systems from DESIGN.md
Build a new app from a preset, install every component, restyle it from a DESIGN.md, then render a design system page.
Trigger phrases: "build me a design system using ", "apply this DESIGN.md", "create a showcase / design system page", "make shadcn look like ".
Contents
- Inputs to confirm
- Step 1: Scaffold
- Step 2: Install everything
- Step 3: Read the DESIGN.md
- Step 4: Map tokens to the theme
- Step 5: Map component recipes to variants
- Step 6: Build the design system page (design-system-page.md)
- Step 7: Verify
- Report back
Inputs to Confirm
If the DESIGN.md path can't be read (macOS privacy blocks ~/Downloads and ~/Desktop for some hosts), ask the user to copy it into the working directory. Don't guess its contents.
Step 1: Scaffold
With a preset code from the user:
Without one, pick the style whose geometry is closest to the DESIGN.md and pass it with --base:
Then:
init with neither --preset nor --base stops at an interactive library prompt, even with -y. Always pass one of them, plus --no-monorepo.
Picking a style
The theme gets replaced by the DESIGN.md anyway. The style decides geometry the CSS variables can't reach: control padding, density, how rounded and how raised the components are. Read the DESIGN.md's radius scale, control heights, shadows and layout density, then pick:
State the choice and the reason in one line ("Picked maia: 40px controls, 12–16px cards, generous padding"). If the user names a style, use it. Read base, style, iconLibrary, tailwindCssFile and aliases from info before writing any code.
Step 2: Install Everything
Count the component files on disk. Never quote a component count from memory.
Then wire up the providers in the app root:
- Wrap the app in
TooltipProvider. - Base UI: wrap the app in
Toasterfrom thetoastcomponent and calltoast.add({ title, description, type }). Radix: render<Toaster />fromsonner.
Then typecheck the app sources. In Vite apps, the root tsc --noEmit checks nothing because the root tsconfig only has project references:
Fix generated files that fail strict checks (for example, an unused React import) before moving on, or vite build will fail.
Step 3: Read the DESIGN.md
DESIGN.md files usually carry YAML frontmatter (colors, typography, rounded, spacing, components) and prose sections (Overview, Colors, Typography, Layout, Elevation, Shapes, Components, Do's and Don'ts, Responsive, Known Gaps). Some only have prose with {colors.x} references. Handle both.
Long files exceed one read. Grep the headings first, then read frontmatter, Do's and Don'ts, Iteration Guide and Known Gaps in full. Those sections hold the rules that override defaults.
Extract into a working table before editing anything:
Step 4: Map Tokens to the Theme
Edit only tailwindCssFile. Keep hex values when the DESIGN.md gives hex. Don't convert them to OKLCH.
Role mapping
Every token without a shadcn slot gets a variable in :root (and .dark when it changes) and a registration in @theme inline:
Radius
A DESIGN.md radius scale rarely fits the --radius multipliers. Pin each step in @theme inline instead. These are the classes base-nova components use:
Replace the existing --radius-* lines in @theme inline rather than adding a second block. Confirm the classes for the installed style:
rounded-[min(var(--radius-md),Npx)] caps small buttons and select triggers. Edit the cap when the DESIGN.md wants rounder small controls.
Elevation
Override Tailwind's shadow scale in @theme, not @theme inline. Copy multi-layer shadows verbatim. Set --shadow-xs to 0 0 #0000 when the system is hairline-only, because inputs and outline buttons use it.
Fonts
Brand fonts are usually licensed. Use the substitutes the DESIGN.md names, installed from Fontsource with the project's package manager, and import every face you reference at the top of the CSS file:
--font-heading styles small component titles (CardTitle, DialogTitle, SheetTitle). Point it at the display face only when that face reads well at 16px. Otherwise keep it on the sans and use display tokens for page headings.
Type scale
Turn every typography token into a type-* utility. Don't use --text-* theme keys for this, because cn() treats unknown text-* classes as colors and drops whichever comes first when one sits next to text-muted-foreground.
- Clamp display sizes so mobile works. Convert pixel tracking to
em(-1px / 48px = -0.021em) so the ratio holds as the size shrinks. - Respect the rules on tracking (none below a size) and weight (display never bold).
Dark mode
- DESIGN.md defines dark surfaces (product mockups, footers): put them in
.dark. Because shadcn's@custom-variant dark (&:is(.dark *))scopes to descendants,className="dark"on any section renders every component inside it with dark tokens. Use it for dark bands, featured pricing cards and footers. - DESIGN.md is light-only: derive
.darkfrom the brand's known dark surfaces and tell the user it's derived.
Focus
Match the documented focus treatment:
- Ring with alpha (for example "3px coral at 15%"): replace
ring-ring/50with the documented alpha on field components (input,textarea,input-group,select,native-select,combobox,input-otp). - Solid outline with offset: add an unlayered rule so it beats
outline-none, and cancel the ring shadow:
This covers actions only. Field controls keep their ring. When the DESIGN.md applies the outline to fields too, add input, textarea, select, [role="combobox"] to the selector.
Step 5: Map Component Recipes to Variants
Restyle by editing the cva variants in the installed component source. Keep existing variant names so usage stays standard. Add a variant only when the DESIGN.md defines a distinct recipe.
Control heights move together. When the button height changes, change the field controls to match, or forms misalign. In base-nova the 32px default lives in:
Re-grep before editing (grep -n "\bh-8\b\|size-8\b" <ui>/*.tsx); other styles use different values.
States. Follow the documented states exactly. If the DESIGN.md says "darken on press only", use active: instead of hover:. Keep hover on ghost buttons and menu items even when the spec omits it, and tell the user you did.
Hard rules. Turn each "Don't" into a check before you finish, for example: no radius outside the scale, no accent color on buttons, no bold display type.
Step 6: Build the Design System Page
Follow design-system-page.md. It sets the section outline, how to present each foundation, the component tiers and block anatomy, pinned state matrices, edge cases, do/don't pairs, and recipes.
In short:
- Foundations first: color roles as contrast-checked pairs, palette, type specimen table, spacing, radius and elevation ladders.
- Components by tier: primitives get a variant × state matrix, size ladder and icon row. Composed components get a typical example, additions and edge cases. Overlays get real triggers.
- Then rendered do/don't pairs for the DESIGN.md's rules, the DESIGN.md's named recipes rebuilt from components, and one example screen.
Copy the helpers from assets/showcase/ (preview-states.css, state-matrix.tsx, color-pair.tsx). Put sections in src/showcase/<section>.tsx (Vite) or app/design-system/ (Next.js). Write copy in the brand's voice.
Known traps
Coverage check
It lists every component file that no showcase file imports. Fix the list until it's empty. add --all installs both toast and sonner in Base UI projects; show sonner in Feedback next to toast so the list can reach zero.
Step 7: Verify
Start the dev server and check it in a browser:
- App typecheck passes (see Step 2).
- No console errors.
- Loads at
scrollY === 0. Anything else means a component is stealing scroll on mount. - No horizontal overflow at 375px and 1280px:
document.documentElement.scrollWidth <= innerWidth. - Screenshot the hero, Foundations, one form section and one dark band. Compare against the DESIGN.md: canvas color, CTA color, display font, radius, focus ring.
- Toggle dark mode once.
Report Back
- App path, dev URL, component count from disk.
- The style picked (when no preset was given) and why.
- What maps where: colors, fonts (and substitutes), radius, shadows, focus.
- Contrast pairs under 4.5:1, including ones the DESIGN.md itself specifies.
- Every component file you edited and why.
- Every deliberate deviation from the DESIGN.md (derived dark mode, kept hover, substituted fonts).