—/Tool
shadcn/ui theme generator with a live preview.
Pick a neutral, a brand colour and a radius. Get all 31 colour tokens for light and dark, in OKLCH.
Copy a globals.css that drops straight into Tailwind v4.
02/Preview
- background#ffffff / #09090b
- foreground#09090b / #fafafa
- card#ffffff / #18181b
- card-foreground#09090b / #fafafa
- popover#ffffff / #18181b
- popover-foreground#09090b / #fafafa
- primary#4f39f6 / #5e5afb
- primary-foreground#fafafa / #fafafa
- secondary#f4f4f5 / #27272a
- secondary-foreground#18181b / #fafafa
- muted#f4f4f5 / #27272a
- muted-foreground#71717b / #9f9fa9
- accent#f4f4f5 / #27272a
- accent-foreground#18181b / #fafafa
- destructive#e40016 / #ff6568
- border#e4e4e7 / white 10%
- input#e4e4e7 / white 15%
- ring#4f39f6 / #7d87ff
- chart-1#4f39f6 / #605eff
- chart-2#bdc6ff / #d5dcff
- chart-3#605dff / #7982ff
- chart-4#280094 / #3d00d5
- chart-5#8a96ff / #a5b1ff
- sidebar#fafafa / #18181b
- sidebar-foreground#09090b / #fafafa
- sidebar-primary#4f39f6 / #5e5afb
- sidebar-primary-foreground#fafafa / #fafafa
- sidebar-accent#f4f4f5 / #27272a
- sidebar-accent-foreground#18181b / #fafafa
- sidebar-border#e4e4e7 / white 10%
- sidebar-ring#4f39f6 / #7d87ff
- How to readLight mode left, dark mode right
/* shadcn/ui theme: zinc · indigo oklch(0.511 0.262 276.966) · brand primary · neutral accent · brand charts · radius 0.625rem */
@import "tailwindcss";
@import "tw-animate-css";
@custom-variant dark (&:is(.dark *));
@theme inline {
--color-background: var(--background);
--color-foreground: var(--foreground);
--font-sans: var(--font-geist-sans);
--font-mono: var(--font-geist-mono);
--color-sidebar-ring: var(--sidebar-ring);
--color-sidebar-border: var(--sidebar-border);
--color-sidebar-accent-foreground: var(--sidebar-accent-foreground);
--color-sidebar-accent: var(--sidebar-accent);
--color-sidebar-primary-foreground: var(--sidebar-primary-foreground);
--color-sidebar-primary: var(--sidebar-primary);
--color-sidebar-foreground: var(--sidebar-foreground);
--color-sidebar: var(--sidebar);
--color-chart-5: var(--chart-5);
--color-chart-4: var(--chart-4);
--color-chart-3: var(--chart-3);
--color-chart-2: var(--chart-2);
--color-chart-1: var(--chart-1);
--color-ring: var(--ring);
--color-input: var(--input);
--color-border: var(--border);
--color-destructive: var(--destructive);
--color-accent-foreground: var(--accent-foreground);
--color-accent: var(--accent);
--color-muted-foreground: var(--muted-foreground);
--color-muted: var(--muted);
--color-secondary-foreground: var(--secondary-foreground);
--color-secondary: var(--secondary);
--color-primary-foreground: var(--primary-foreground);
--color-primary: var(--primary);
--color-popover-foreground: var(--popover-foreground);
--color-popover: var(--popover);
--color-card-foreground: var(--card-foreground);
--color-card: var(--card);
--radius-sm: calc(var(--radius) - 4px);
--radius-md: calc(var(--radius) - 2px);
--radius-lg: var(--radius);
--radius-xl: calc(var(--radius) + 4px);
}
:root {
--radius: 0.625rem;
--background: oklch(1 0 0);
--foreground: oklch(0.141 0.005 285.823);
--card: oklch(1 0 0);
--card-foreground: oklch(0.141 0.005 285.823);
--popover: oklch(1 0 0);
--popover-foreground: oklch(0.141 0.005 285.823);
--primary: oklch(0.511 0.262 276.966);
--primary-foreground: oklch(0.985 0 0);
--secondary: oklch(0.967 0.001 286.375);
--secondary-foreground: oklch(0.21 0.006 285.885);
--muted: oklch(0.967 0.001 286.375);
--muted-foreground: oklch(0.552 0.016 285.938);
--accent: oklch(0.967 0.001 286.375);
--accent-foreground: oklch(0.21 0.006 285.885);
--destructive: oklch(0.577 0.245 27.325);
--border: oklch(0.92 0.004 286.32);
--input: oklch(0.92 0.004 286.32);
--ring: oklch(0.511 0.262 276.966);
--chart-1: oklch(0.511 0.262 276.966);
--chart-2: oklch(0.84 0.08 276.966);
--chart-3: oklch(0.58 0.233 276.966);
--chart-4: oklch(0.32 0.198 276.966);
--chart-5: oklch(0.71 0.153 276.966);
--sidebar: oklch(0.985 0 0);
--sidebar-foreground: oklch(0.141 0.005 285.823);
--sidebar-primary: oklch(0.511 0.262 276.966);
--sidebar-primary-foreground: oklch(0.985 0 0);
--sidebar-accent: oklch(0.967 0.001 286.375);
--sidebar-accent-foreground: oklch(0.21 0.006 285.885);
--sidebar-border: oklch(0.92 0.004 286.32);
--sidebar-ring: oklch(0.511 0.262 276.966);
}
.dark {
--background: oklch(0.141 0.005 285.823);
--foreground: oklch(0.985 0 0);
--card: oklch(0.21 0.006 285.885);
--card-foreground: oklch(0.985 0 0);
--popover: oklch(0.21 0.006 285.885);
--popover-foreground: oklch(0.985 0 0);
--primary: oklch(0.571 0.232 276.966);
--primary-foreground: oklch(0.985 0 0);
--secondary: oklch(0.274 0.006 286.033);
--secondary-foreground: oklch(0.985 0 0);
--muted: oklch(0.274 0.006 286.033);
--muted-foreground: oklch(0.705 0.015 286.067);
--accent: oklch(0.274 0.006 286.033);
--accent-foreground: oklch(0.985 0 0);
--destructive: oklch(0.704 0.191 22.216);
--border: oklch(1 0 0 / 10%);
--input: oklch(1 0 0 / 15%);
--ring: oklch(0.671 0.176 276.966);
--chart-1: oklch(0.581 0.232 276.966);
--chart-2: oklch(0.9 0.049 276.966);
--chart-3: oklch(0.66 0.183 276.966);
--chart-4: oklch(0.42 0.26 276.966);
--chart-5: oklch(0.78 0.113 276.966);
--sidebar: oklch(0.21 0.006 285.885);
--sidebar-foreground: oklch(0.985 0 0);
--sidebar-primary: oklch(0.571 0.232 276.966);
--sidebar-primary-foreground: oklch(0.985 0 0);
--sidebar-accent: oklch(0.274 0.006 286.033);
--sidebar-accent-foreground: oklch(0.985 0 0);
--sidebar-border: oklch(1 0 0 / 10%);
--sidebar-ring: oklch(0.671 0.176 276.966);
}
@layer base {
* {
@apply border-border outline-ring/50;
}
body {
@apply bg-background text-foreground;
}
}
06/About
- Output
- globals.css for shadcn/ui on Tailwind v4
- Colour space
- OKLCH, kept inside sRGB
- Tokens
- 31 colours × light and dark, plus radius
- Privacy
- Generated in your browser, nothing stored
How the theme generator works
shadcn/ui components don’t hard-code colours. Every button, card and menu reads from a small set of CSS variables: --background, --primary, --muted, --ring and so on. Change those variables and every component follows. This tool writes the whole set from a handful of decisions and shows the result on a real layout before you commit to it.
What each choice controls
- Neutral sets the greys: backgrounds, cards, borders, muted text. Zinc, slate, gray, stone and neutral are Tailwind’s own scales. Tinted takes zinc’s lightness and adds a trace of your brand hue.
- Brand colour drives the focus ring and the charts, and the primary button if you choose. Adjust it with lightness, chroma and hue sliders. OKLCH keeps lightness even across hues.
- Primary fills buttons, checkboxes and switches with the brand colour, or keeps shadcn’s near-black default.
- Accent is the hover surface behind ghost buttons and menu items, not a brand colour. Tinted gives it a faint wash of the brand hue.
- Radius sets
--radius. Components derive their own corners from it, from 4px below it to 4px above.
Contrast checks
Every pair of text and fill the components actually use is checked against WCAG 2: 4.5:1 for text, 3:1 for the focus ring. Text on a filled button automatically picks whichever end of the neutral scale reads better. If the brand colour is too light for a focus ring on white, the ring is darkened until it passes. One thing to know: shadcn’s own default puts muted text on the muted surface at about 4.4:1, just under AA. The check shows it rather than hiding it.
How to use the output
- Set up shadcn/ui in a Tailwind v4 project with
npx shadcn@latest init. - Replace the contents of
app/globals.css(or your main CSS file) with the generated file. - The file maps
--font-sansto Geist, as the Next.js starter does. Change those two lines if you use another font.
Note
Colours are mapped into sRGB, so the hex values match what most screens show. A few very saturated presets lose a little chroma to fit. The first line of the file records the settings, so you can recreate the theme later.