cssgridgen

shadcn Theme Generator

Primary, neutral and radius in — the full token set out.

Create projectDeploy your new project in one click.
acme-web
Next.js
PrimarySecondaryOutlineDestructive

--chart-1 … --chart-5

globals.css

Replace the :root and .dark blocks in your globals.css. Leave the @theme inline block alone — it maps these tokens onto Tailwind utilities and does not change per theme.

:root {
  --radius: 0.625rem;
  --background: oklch(1 0.013 258);
  --foreground: oklch(0.145 0.013 258);
  --card: oklch(1 0.013 258);
  --card-foreground: oklch(0.145 0.013 258);
  --popover: oklch(1 0.013 258);
  --popover-foreground: oklch(0.145 0.013 258);
  --primary: oklch(0.546 0.215 262.881);
  --primary-foreground: oklch(0.985 0 0);
  --secondary: oklch(0.97 0.013 258);
  --secondary-foreground: oklch(0.205 0.013 258);
  --muted: oklch(0.97 0.013 258);
  --muted-foreground: oklch(0.556 0.013 258);
  --accent: oklch(0.97 0.013 258);
  --accent-foreground: oklch(0.205 0.013 258);
  --destructive: oklch(0.577 0.245 27.325);
  --border: oklch(0.922 0.013 258);
  --input: oklch(0.922 0.013 258);
  --ring: oklch(0.666 0.151 262.881);
  --chart-1: oklch(0.6 0.14 262.881);
  --chart-2: oklch(0.65 0.14 309.881);
  --chart-3: oklch(0.6 0.14 356.881);
  --chart-4: oklch(0.65 0.14 43.881);
  --chart-5: oklch(0.6 0.14 90.881);
  --sidebar: oklch(0.985 0.013 258);
  --sidebar-foreground: oklch(0.145 0.013 258);
  --sidebar-primary: oklch(0.546 0.215 262.881);
  --sidebar-primary-foreground: oklch(0.985 0 0);
  --sidebar-accent: oklch(0.97 0.013 258);
  --sidebar-accent-foreground: oklch(0.205 0.013 258);
  --sidebar-border: oklch(0.922 0.013 258);
  --sidebar-ring: oklch(0.666 0.151 262.881);
}

.dark {
  --background: oklch(0.145 0.013 258);
  --foreground: oklch(0.985 0.013 258);
  --card: oklch(0.205 0.013 258);
  --card-foreground: oklch(0.985 0.013 258);
  --popover: oklch(0.205 0.013 258);
  --popover-foreground: oklch(0.985 0.013 258);
  --primary: oklch(0.62 0.194 262.881);
  --primary-foreground: oklch(0.16 0.013 258);
  --secondary: oklch(0.269 0.013 258);
  --secondary-foreground: oklch(0.985 0.013 258);
  --muted: oklch(0.269 0.013 258);
  --muted-foreground: oklch(0.708 0.013 258);
  --accent: oklch(0.269 0.013 258);
  --accent-foreground: oklch(0.985 0.013 258);
  --destructive: oklch(0.704 0.191 22.216);
  --border: oklch(1 0 0 / 10%);
  --input: oklch(1 0 0 / 15%);
  --ring: oklch(0.556 0.013 258);
  --chart-1: oklch(0.62 0.14 262.881);
  --chart-2: oklch(0.68 0.14 309.881);
  --chart-3: oklch(0.62 0.14 356.881);
  --chart-4: oklch(0.68 0.14 43.881);
  --chart-5: oklch(0.62 0.14 90.881);
  --sidebar: oklch(0.205 0.013 258);
  --sidebar-foreground: oklch(0.985 0.013 258);
  --sidebar-primary: oklch(0.62 0.194 262.881);
  --sidebar-primary-foreground: oklch(0.16 0.013 258);
  --sidebar-accent: oklch(0.269 0.013 258);
  --sidebar-accent-foreground: oklch(0.985 0.013 258);
  --sidebar-border: oklch(1 0 0 / 10%);
  --sidebar-ring: oklch(0.556 0.013 258);
}
Free tool

The greys decide how it feels

A shadcn theme is about forty CSS variables, and only one of them is your brand colour. The rest are greys, and they cover most of the page — which is why two themes with the same primary can feel completely different. This generates the whole set from a colour, a neutral family and a radius, in the oklch format the current themes use.

How to use it

  1. Pick a primary colour

    Any hex. It is converted to oklch, which is the format shadcn themes are authored in and the reason a generated palette stays coherent.

  2. Choose a neutral family

    Slate, gray, zinc, stone or flat neutral. This tints every grey in the theme and matters more than the primary on a typical page.

  3. Set the radius

    One value that Tailwind derives the entire radius scale from.

  4. Check both modes

    Toggle light and dark under the preview. The dark primary is lifted automatically so it keeps contrast on a dark ground.

  5. Paste into globals.css

    Replace the :root and .dark blocks. Leave @theme inline as it is.

Why oklch

In hex or HSL, darkening a colour tends to shift its hue and drain its saturation unpredictably. oklch separates lightness, chroma and hue, so a palette generated by moving lightness stays the same colour the whole way down. It is also perceptually uniform, meaning equal steps look equal — which is what makes the muted, border and accent tokens sit correctly against each other.

Accent is not a second brand colour

In the stock themes accent is a near-white grey used for hover and highlight states, not a contrasting colour. Setting it to something vivid is the most common way a shadcn theme starts to look loud, because it fires on every menu item and every hover.

Dark mode is the same tokens

Components never reference a light or dark value — they reference --primary, and the .dark block redefines it. That is why theming is a CSS-only change and no component needs to know which mode it is in. The generator lifts the primary's lightness for dark mode so it does not disappear against the background.

Theming the charts too

The five --chart-* tokens are generated from your primary's hue, spaced around the wheel so categorical series stay distinguishable. See them in use in the chart generator.

Frequently asked questions

How do I change the shadcn theme colours?
Replace the :root and .dark blocks in your globals.css. Every component reads those tokens, so nothing else needs touching — no component edits, no rebuild of class names. Leave the @theme inline block alone; it maps the tokens onto Tailwind utilities and is the same for every theme.
Why does shadcn use oklch instead of hex?
Because oklch separates lightness, chroma and hue, so you can darken a colour without it shifting hue or going muddy — which is exactly what generating a coherent palette requires. It is also perceptually uniform, so equal lightness steps actually look equal.
What is the difference between primary and accent?
primary is your brand colour, used for the main action on a screen. accent is a subtle neutral used for hover and highlight states — in the default themes it is a light grey, not a second brand colour. Making accent vivid is the usual reason a shadcn theme starts to look noisy.
What does the neutral family actually change?
It tints every grey in the theme: backgrounds, borders, muted text, cards. Slate is cool, stone is warm, neutral is dead flat. Because greys cover most of the page, this choice affects the overall feel far more than the primary colour does.
How does --radius work?
It is a single value that Tailwind derives the whole radius scale from — rounded-sm through rounded-4xl are all computed from it. Changing it reshapes every component at once, which is why it belongs in the theme rather than on individual components.
Do I need to change anything for dark mode?
No. Dark mode overrides the same token names inside a .dark selector, so components never reference a light or dark value directly. Add the dark class to html and everything switches.