shadcn Theme Generator
Primary, neutral and radius in — the full token set out.
--chart-1 … --chart-5
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);
}
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
-
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.
-
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.
-
Set the radius
One value that Tailwind derives the entire radius scale from.
-
Check both modes
Toggle light and dark under the preview. The dark primary is lifted automatically so it keeps contrast on a dark ground.
-
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?
: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?
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?
How does --radius work?
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?
.dark selector, so components never reference a light or dark value directly. Add the dark class to html and everything switches.