shadcn/ui doesn't ship a theme object or a config file for colors. Every component reads its colors, radius and fonts from CSS custom properties, so theming means changing a handful of variables in your global stylesheet. This guide walks through how those variables fit together in Tailwind CSS v4, and how to swap in a complete theme in under a minute.
The three parts of a shadcn/ui theme
Open app/globals.css in a project created with npx shadcn@latest init and you'll find three pieces:
:root: the light-mode values for every token..dark: the dark-mode values, applied when thedarkclass is on a parent element (usually<html>).@theme inline: a mapping that turns those variables into Tailwind utilities such asbg-primaryandtext-muted-foreground.
@import "tailwindcss";
@import "tw-animate-css";
@custom-variant dark (&:is(.dark *));
:root {
--radius: 0.625rem;
--background: oklch(1 0 0);
--foreground: oklch(0.145 0 0);
--primary: oklch(0.205 0 0);
--primary-foreground: oklch(0.985 0 0);
/* …secondary, muted, accent, destructive, border, input, ring, charts, sidebar */
}
.dark {
--background: oklch(0.145 0 0);
--foreground: oklch(0.985 0 0);
--primary: oklch(0.922 0 0);
--primary-foreground: oklch(0.205 0 0);
/* … */
}
@theme inline {
--color-background: var(--background);
--color-foreground: var(--foreground);
--color-primary: var(--primary);
--color-primary-foreground: var(--primary-foreground);
--radius-lg: var(--radius);
/* … */
}
Because of @theme inline, a utility like bg-primary compiles to background-color: var(--primary). Change --primary and every button, badge and focus ring follows.
The tokens and what they control
Tokens come in background / foreground pairs. The base name is a surface color; the -foreground variant is the text and icon color that sits on top of it.
| Token | Used for |
|---|---|
background / foreground | The page and its default text |
card / card-foreground | Cards and other raised surfaces |
popover / popover-foreground | Menus, selects, popovers and tooltips |
primary / primary-foreground | Default buttons, active states, key accents |
secondary / secondary-foreground | Secondary buttons and quieter surfaces |
muted / muted-foreground | Subtle backgrounds and secondary text |
accent / accent-foreground | Hover and selected states in menus and lists |
destructive | Delete buttons and error states |
border, input, ring | Borders, form-field borders and focus rings |
chart-1 … chart-5 | Chart series colors |
sidebar-* | The sidebar component's own surface, text, active item and border |
The most common theming mistake is changing a surface without its foreground. If you set --primary to a light
yellow, also set --primary-foreground to a dark color, or button labels become unreadable.
Radius, fonts, shadows and spacing
Colors aren't the only thing a theme controls:
--radiusis the base corner radius. Tailwind'srounded-smthroughrounded-xlare derived from it, so one value reshapes every component.--font-sans,--font-serifand--font-monoset the font stacks behindfont-sans,font-serifandfont-mono. See Fonts in shadcn/ui for loading Google Fonts properly.--shadow-*variables (from--shadow-2xsto--shadow-2xl) replace Tailwind's default shadow scale, which is how neo-brutalist themes get hard offset shadows.--spacingis Tailwind v4's base spacing unit (0.25rem by default). Everyp-4orgap-2is a multiple of it.
Install a theme in one command
Every theme on shadcnthemes.com is published as a shadcn registry item, so the CLI can write it into your globals.css for you:
npx shadcn@latest add https://shadcnthemes.com/r/claude.json
The CLI merges the theme's light, dark and shared variables into your stylesheet, leaving your other CSS alone. Prefer to do it by hand? Every theme page has a Copy CSS button. Paste the result over your existing :root, .dark and @theme inline blocks.
Make your own
Start from any theme in the gallery, or from scratch, and open it in the editor. You can change every token for both modes, pick fonts, tune radius and shadows, and watch it apply live to real dashboards and landing pages.
Quick checklist
- Edit pairs, not single colors, and check contrast. The editor flags anything under WCAG AA.
- Tune dark mode separately. Inverting light-mode colors rarely looks good.
- Keep
ringclose toprimaryso focus states look intentional. - Set chart colors that are distinct from each other in both modes.