shadcn/ui
by shadcnHow it's built
#Color system
shadcn/ui doesn't generate a palette. It ships a fixed set of semantic CSS variables — borrowed from Tailwind's color scales — that you re-theme by swapping values. In v4 those values are OKLCH.
Every surface has a foreground
Tokens come in pairs: a surface color and the -foreground meant to sit on it. Components reference the pair (bg-primary text-primary-foreground), so a re-theme never breaks contrast.
Light and dark
Values are defined once, then overridden under .dark. The token names never change — only what they resolve to.
One real choice: the neutral base
The grays are the only thing you pick up front. Each base tints every neutral token toward a hue; the semantic structure is identical across all five.
Explore
#Colors
Every token resolved for the picks a shadcn user actually makes — base gray, color theme, and mode. Watch the same UI re-theme, and see the exact Tailwind step behind each value (borrowed steps highlighted).
Live preview
| Token | Value | Tailwind | Usage |
|---|---|---|---|
| Surfaces | |||
| background | white | The app canvas and its default text. | |
| foreground | zinc-950 | Text painted on background. | |
| card | white | Raised surfaces — cards and panels. | |
| card-foreground | zinc-950 | Text painted on card. | |
| popover | white | Floating surfaces — menus, dropdowns, popovers. | |
| popover-foreground | zinc-950 | Text painted on popover. | |
| Semantic roles | |||
| primary | zinc-900 | Primary actions and emphasis. | |
| primary-foreground | zinc-50 | Text painted on primary. | |
| secondary | zinc-100 | Secondary buttons and low-emphasis fills. | |
| secondary-foreground | zinc-900 | Text painted on secondary. | |
| muted | zinc-100 | Muted fills; the foreground is the default secondary text. | |
| muted-foreground | zinc-500 | Text painted on muted. | |
| accent | zinc-100 | Hover and active surface highlights. | |
| accent-foreground | zinc-900 | Text painted on accent. | |
| destructive | red-600 | Destructive actions and errors. The base-ui button renders it as a soft fill: bg-destructive/10 (dark /20) with text-destructive. | |
| Borders & focus | |||
| border | zinc-200 | Default separators and card borders. | |
| input | zinc-200 | Borders on inputs and controls. | |
| ring | zinc-400 | The focus ring. | |
| Charts | |||
| chart-1 | zinc-300 | Data series 1. | |
| chart-2 | zinc-500 | Data series 2. | |
| chart-3 | zinc-600 | Data series 3. | |
| chart-4 | zinc-700 | Data series 4. | |
| chart-5 | zinc-800 | Data series 5. | |
| Sidebar | |||
| sidebar | zinc-50 | Sidebar surface and text. | |
| sidebar-foreground | zinc-950 | Text painted on sidebar. | |
| sidebar-primary | zinc-900 | Active sidebar item. | |
| sidebar-primary-foreground | zinc-50 | Text painted on sidebar-primary. | |
| sidebar-accent | zinc-100 | Hovered sidebar item. | |
| sidebar-accent-foreground | zinc-900 | Text painted on sidebar-accent. | |
| sidebar-border | zinc-200 | Sidebar separators. | |
| sidebar-ring | zinc-400 | Sidebar focus ring. | |
What gets borrowed
Almost every token is the base gray. A handful reach outside it — and that's the whole of shadcn's color choices.
- destructive is always red; in dark mode border and input are translucent white, and sidebar-primary is blue.
- neutral/stone/zinc tint the charts to their own gray; gray/slate keep Tailwind's colorful default series.
- A color theme repaints primary, ring, and their sidebar twins with a colored step — everything else stays the base gray. (The ring is a lighter/darker shade than the primary, and shadcn's “green” is built on lime.)
Every value is an exact Tailwind step — the base grays and the color themes alike (shadcn annotates each in its own source). Highlighted chips are the steps that reach outside the chosen base gray.
Explore
#Usage
Beyond the declared tokens, shadcn's component styles derive colours at the point of use — token opacity modifiers, color-mix blends, and relative-oklch tints. These are extracted from style-nova, shadcn's default style, so you can see exactly where each derivation is used.
Colours that exist only at point of use in component styles — opacity-modified tokens, color-mix, and relative-oklch tints. Extracted from style-nova, shadcn’s default style.
Opacity
opacity28 expressions| Preview | Expression | Used by |
|---|---|---|
bg-background/10 | ||
bg-background/20 | ||
bg-destructive/10 | ||
bg-destructive/20 | ||
bg-destructive/30 | ||
bg-foreground/10 | ||
bg-foreground/5 | ||
bg-input/30 | ||
bg-input/50 | ||
bg-input/80 | ||
bg-muted/50 | ||
bg-popover/70 | ||
bg-primary/10 | ||
bg-primary/5 | ||
bg-primary/80 | ||
bg-secondary/80 | ||
border-border/50 | ||
border-destructive/40 | ||
border-destructive/50 | ||
border-input/30 | ||
border-primary/20 | ||
border-primary/30 | ||
ring-destructive/20 | ||
ring-destructive/40 | ||
ring-foreground/10 | ||
ring-ring/50 | ||
text-destructive/90 | ||
text-sidebar-foreground/70 |
Color-mix
color-mix2 expressions| Preview | Expression | Used by |
|---|---|---|
bg-[color-mix(in oklch,var(--muted),var(--foreground) 5%)] | ||
bg-[color-mix(in oklch,var(--secondary),var(--foreground) 5%)] |
Literal
literal6 expressions| Preview | Expression | Used by |
|---|---|---|
bg-[oklch(from var(--primary) 0.3 calc(c*0.4) h)] Relative-oklch tint derived from --primary. | ||
bg-[oklch(from var(--primary) 0.35 calc(c*0.5) h)] Relative-oklch tint derived from --primary. | ||
bg-[oklch(from var(--primary) 0.88 calc(c*0.5) h)] Relative-oklch tint derived from --primary. | ||
bg-[oklch(from var(--primary) 0.93 calc(c*0.4) h)] Relative-oklch tint derived from --primary. | ||
bg-black/10 | ||
bg-white |