Live preview
Styled by its token map
acme.example

shadcn/ui

Design Systems

The copy-paste component aesthetic of the modern React/Next.js era: Radix primitives styled with Tailwind, a neutral OKLCH-defined palette (white bg, near-black #0a0a0a foreground, #171717 primary, #e5e5e5 borders), 0.625rem radius, Geist or Inter type, CSS-variable theming, and instant dark mode by flipping the neutral scale.

Palette
bg
#ffffff
text
#0a0a0a
accent
#171717
muted
#f5f5f5
text-muted
#737373
border
#e5e5e5
destructive
#dc2626

About this style

shadcn/ui, released by @shadcn in 2023, inverted the component-library contract: instead of installing a package you copy the source into your repo, own it, and theme it through a small set of CSS variables. Styled with Tailwind over Radix primitives, its default 'neutral' theme — white canvas, near-black #171717 primary, #e5e5e5 hairlines, 10px radii, Geist or Inter at 14px — became the de facto look of 2023–26 startups, v0-generated apps, and AI-tool dashboards. Current versions define colors in OKLCH (e.g. --foreground: oklch(0.145 0 0), --border dark: oklch(1 0 0 / 10%)); the hex values recorded here are the sRGB equivalents, matching Tailwind's neutral scale. Choose it for React/Next.js products that need credible polish fast and full control of component source; fight it (or at least re-seed the primary and radius) if you need the product to not look like every other shadcn app.

The default pairs pass AA: #0a0a0a on white ~19.8:1, muted-foreground #737373 ~4.7:1 (borderline — avoid it below 12px), white on primary #171717 ~16:1
Radix primitives supply focus management, ARIA wiring, and keyboard support — keep the primitives when restyling
The 3px --ring focus ring at 50% opacity must stay visible against custom backgrounds; re-check it when theming beyond neutral
---
name: shadcn-ui
description: Apply the shadcn/ui visual design system when building or restyling websites and UI. Use whenever the user asks to build, theme, restyle, or "make it look like" shadcn/ui, mentions shadcn, shadcn ui, Radix + Tailwind, or describes neutral gray scale, near-black primary, CSS-variable theming (--background, --primary), 0.625rem (10px) radius — even if they don't name the style explicitly. Do NOT use for non-visual tasks or when another named design system is requested.
license: MIT
---

# shadcn/ui Design System

The copy-paste component aesthetic of the modern React/Next.js era: Radix primitives styled with Tailwind, a neutral OKLCH-defined palette (white bg, near-black #0a0a0a foreground, #171717 primary, #e5e5e5 borders), 0.625rem radius, Geist or Inter type, CSS-variable theming, and instant dark mode by flipping the neutral scale.

Apply this system holistically: colors, type, spacing, radius, borders, shadows, and motion together produce the look. Token values come from the officially published token set. When in doubt, match the reference sites listed at the end.

## When to use

- Building a new page or component that should read as shadcn/ui.
- Restyling existing UI to this aesthetic.
- The user names the style, an alias (shadcn, shadcn ui, Radix + Tailwind, new-york style), or describes its traits: neutral gray scale, near-black primary; CSS-variable theming (--background, --primary); 0.625rem (10px) radius; hairline #e5e5e5 borders with soft shadows; Radix-driven accessible primitives; dark mode by scale inversion.

## Design tokens

### Color palette

- --background — oklch(1 0 0): `#ffffff` (--color-bg)
- --foreground — oklch(0.145 0 0), Tailwind neutral-950: `#0a0a0a` (--color-text)
- --primary — oklch(0.205 0 0), near-black neutral-900: `#171717` (--color-accent)
- --muted / --secondary — oklch(0.97 0 0): `#f5f5f5` (--color-muted)
- --muted-foreground — oklch(0.556 0 0), neutral-500: `#737373` (--color-text-muted)
- --border / --input — oklch(0.922 0 0), neutral-200: `#e5e5e5` (--color-border)
- --destructive — oklch(0.577 0.245 27.325), Tailwind red-600: `#dc2626` (--color-destructive)

### Dark mode overrides

When building dark mode, override these roles (all other tokens stay the same):

- --background dark — oklch(0.145 0 0): `#0a0a0a` (--color-bg)
- --foreground dark — oklch(0.985 0 0): `#fafafa` (--color-text)
- --primary dark — oklch(0.922 0 0); primary flips light: `#e5e5e5` (--color-accent)
- --muted dark — oklch(0.269 0 0): `#262626` (--color-muted)
- --muted-foreground dark — oklch(0.708 0 0): `#a3a3a3` (--color-text-muted)
- --border dark — oklch(1 0 0 / 10%), 10% white: `#ffffff1a` (--color-border)

### Typography

- Display / headings: Geist (fallback: Inter, system-ui, sans-serif)
- Body: Geist (fallback: Inter, system-ui, sans-serif)
- Mono / data: Geist Mono (fallback: ui-monospace, SFMono-Regular, Menlo, monospace)
- Type scale: 1.25 ratio, base 14px — computed steps: 14px / 18px / 22px / 27px / 34px / 43px (body / h5 / h4 / h3 / h2 / h1; scale further for display sizes)
- Headings: weight 600, line-height 1.2, letter-spacing -0.025em
- Body: line-height 1.5, letter-spacing 0

### Spacing, radius, border

- Spacing scale (px): 4, 8, 12, 16, 24, 32, 48, 64 — Tailwind's 4px scale; components default comfortable-compact — 24px card padding (p-6), 8px gaps in forms (space-y-2 per field, gap-4 between groups), text-sm 14px throughout app UI.
- Border radius: sm 6px, md 8px, lg 10px, xl 14px, full 9999px — Driven by --radius: 0.625rem (10px); sm/md derive by subtracting 4px/2px. Buttons and inputs use md, cards lg, pills full.
- Border treatment: 1px solid #e5e5e5 — Hairline neutral borders on cards and inputs; dark mode swaps to 10% white (oklch(1 0 0 / 10%)) so borders stay subordinate.

### Shadows

- xs: `0 1px 2px 0 rgba(0, 0, 0, 0.05)` — Buttons and inputs (shadow-xs)
- sm: `0 1px 3px 0 rgba(0, 0, 0, 0.1), 0 1px 2px -1px rgba(0, 0, 0, 0.1)` — Cards at rest (shadow-sm)
- md: `0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -2px rgba(0, 0, 0, 0.1)` — Popovers, dropdown menus, hover cards
- lg: `0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -4px rgba(0, 0, 0, 0.1)` — Dialogs and sheets

### Layout

- Max content width: 1400px
- Container centered at max 1400px (the shadcn Tailwind container default)
- Dashboard pattern: sidebar (collapsible, icon-rail) + header row + card grid
- Forms compose Label + Input + helper text at space-y-2, grouped in cards with separated footer actions
- Data tables built on TanStack Table with a toolbar of filter inputs and a column-visibility dropdown

### Effects

- Focus rings via ring utilities: 3px ring in --ring neutral at 50% opacity, offset from the control
- Entrance micro-animations from tailwindcss-animate: fade + 2% zoom + 8px slide on popovers and dialogs

### Motion

- Easing: cubic-bezier(0.4, 0, 0.2, 1); durations 150ms / 200ms / 300ms
- Overlays animate data-[state=open]/closed with fade+zoom+slide in under 200ms
- Accordions animate height with the Radix height variable
- Everything else is a 150ms color/shadow transition; no scroll or page choreography

## CSS variables (drop-in)

```css
:root {
  --color-bg: #ffffff;
  --color-text: #0a0a0a;
  --color-accent: #171717;
  --color-muted: #f5f5f5;
  --color-text-muted: #737373;
  --color-border: #e5e5e5;
  --color-destructive: #dc2626;
  --radius-sm: 6px;
  --radius-md: 8px;
  --radius-lg: 10px;
  --radius-xl: 14px;
  --radius-full: 9999px;
  --shadow-xs: 0 1px 2px 0 rgba(0, 0, 0, 0.05);
  --shadow-sm: 0 1px 3px 0 rgba(0, 0, 0, 0.1), 0 1px 2px -1px rgba(0, 0, 0, 0.1);
  --shadow-md: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -2px rgba(0, 0, 0, 0.1);
  --shadow-lg: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -4px rgba(0, 0, 0, 0.1);
  --border-default: 1px solid #e5e5e5;
  --font-display: Geist, Inter, system-ui, sans-serif;
  --font-body: Geist, Inter, system-ui, sans-serif;
  --font-mono: "Geist Mono", ui-monospace, SFMono-Regular, Menlo, monospace;
  --text-base: 14px;
  --leading-heading: 1.2;
  --leading-body: 1.5;
  --tracking-heading: -0.025em;
  --tracking-body: 0;
  --ease: cubic-bezier(0.4, 0, 0.2, 1);
  --duration-fast: 150ms;
  --duration-base: 200ms;
  --duration-slow: 300ms;
}
```

Google Fonts: `<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin><link href="https://fonts.googleapis.com/css2?family=Geist:wght@400;500;600;700&family=Geist+Mono:wght@400&display=swap" rel="stylesheet">`

## Component recipes

- **Nav:** Header: 56–64px, background/95 with backdrop-blur, hairline bottom border, 14px/500 links that brighten from muted-foreground to foreground on hover; or the Sidebar block with icon rail
- **Hero:** Centered stack: optional pill badge, 48–72px tracking-tight semibold headline, muted-foreground subtext at 16–18px, then a near-black primary button beside an outline button
- **Card:** bg white (card token), 1px border, lg radius (10px), shadow-sm, p-6; CardHeader/CardContent/CardFooter slots with a 24px rhythm
- **Button (primary):** --primary #171717 fill, --primary-foreground near-white text, md radius, 36px tall (h-9), 14px/500 label, shadow-xs; hover primary/90
- **Button (secondary):** outline variant: transparent bg, 1px border, foreground text; hover fills with --accent #f5f5f5
- **Form fields:** Label 14px/500; Input h-9, md radius, 1px --input border, transparent bg, shadow-xs; focus adds 3px --ring ring at 50% opacity; error swaps ring and text to destructive

Where this spec is silent (footers, responsive breakpoints, empty states), derive the treatment from the tokens above and the Do/Don't rules — never fall back to generic defaults. Every interactive element needs a visible keyboard focus state consistent with the style (use the accent color or the border treatment, not the browser default).

## Signature element

The near-black primary button on a white card with hairline border, 10px radius, and a whisper of Tailwind shadow — plus the --background/--foreground CSS-variable pairing that made 'add dark mode' a one-class exercise. Spend boldness here; keep everything else quiet.

## Do

- Theme exclusively through the CSS variables (--background, --primary, --radius) so components stay copy-paste portable
- Keep app chrome at text-sm 14px with 500-weight labels — the compact tone is the aesthetic
- Use muted-foreground for every piece of secondary text instead of opacity tweaks
- Let Radix state attributes (data-[state=open]) drive animation and styling

## Don't

- Don't introduce a saturated brand primary without re-deriving the full variable set — the neutral near-black primary is the default look
- Don't mix radii arbitrarily; everything derives from the single --radius token
- Don't heavy-up shadows — nothing at rest exceeds shadow-sm
- Don't fork component styles inline; edit the copied component source once, in one place

## Accessibility notes

- The default pairs pass AA: #0a0a0a on white ~19.8:1, muted-foreground #737373 ~4.7:1 (borderline — avoid it below 12px), white on primary #171717 ~16:1
- Radix primitives supply focus management, ARIA wiring, and keyboard support — keep the primitives when restyling
- The 3px --ring focus ring at 50% opacity must stay visible against custom backgrounds; re-check it when theming beyond neutral

## Reference sites

- shadcn/ui: https://ui.shadcn.com
- shadcn/ui theming docs: https://ui.shadcn.com/docs/theming
- Radix UI primitives: https://www.radix-ui.com

For the exhaustive machine-readable spec, see references/tokens.md and tokens.json in this skill folder.

Install this skill

Claude Code — download the zip, then unzip into your skills folder
unzip shadcn-ui.zip -d ~/.claude/skills/
shadcn/ui — apply as a theme to any shadcn project
npx shadcn add https://claude-design-skills.convoke.software/r/shadcn-ui.json
claude.ai — upload the zip as a custom skill
Settings → Capabilities → Skills → Upload skill → shadcn-ui.zip
Download .zip