Generate coordinated light and dark theme tokens from one brand color — with your choice of dark-mode strategy: .dark class, prefers-color-scheme, or the CSS light-dark() function.
Generated locally in your browser — your colors, settings and code never leave this page.
Dark mode is a second theme, not a filter
Inverting colors breaks interfaces: pure white text on pure black vibrates, saturated brand colors glow, and elevation hierarchy flips. This generator derives both themes from the same OKLCH scales — backgrounds slide to the 950/900 end, text to the 50 tint, and the primary jumps from 600 in light to 400 in dark, because dark UIs need lighter accents to hold contrast. Both text/background pairs are verified to pass WCAG AA before you ever see them.
Three switching strategies — pick per project
- .dark class — you control the toggle in JS, can persist user choice; the Tailwind-native pattern.
- prefers-color-scheme — the OS decides; zero JS; no user override without extra work.
- light-dark() — one declaration carries both values (
--bg: light-dark(#f8fafc, #020617)); leanest CSS, needs 2024-era browsers (Chrome 123+, Safari 17.5+, Firefox 120+), which the output notes.
Worked example (class strategy)
:root {
--bg: #f8fafc; --text: #0f172a; --primary: #4f46e5;
}
.dark {
--bg: #020617; --text: #f8fafc; --primary: #818cf8;
}Best practices
- Set
color-scheme: light darkso form controls and scrollbars follow the theme. - Persist the class-strategy choice (localStorage) and apply it before first paint to avoid the flash of wrong theme.
- Use the side-by-side preview cards here to sanity-check hierarchy — surface must read as “above” background in both modes.
Limitations
- Nine tokens cover surfaces, text, border and primary — status roles come from the Semantic Token Generator, whose scales adapt the same way.
How to use the Light/Dark Theme Generator
- Pick your brand color and neutral base.
- Choose the dark-mode strategy — .dark class, media query, or light-dark().
- Compare the live light and dark cards side by side.
- Copy the CSS (or Tailwind v4 variant) and wire the toggle in your app.
Frequently asked questions
How are the dark values derived?
From the same OKLCH scales as the light values, mirrored: backgrounds move to the 950/900 end, text to the 50 tint, and the primary jumps from 600 to 400 — dark UIs need lighter accents to keep contrast. Both text/background pairs are checked to pass WCAG AA.
Which dark-mode strategy should I choose?
The .dark class if users get a toggle (you control it in JS and can persist the choice); prefers-color-scheme if the OS setting should decide; light-dark() for the leanest modern CSS — one declaration per token — accepting that it needs 2024-era browsers.
Why not just invert colors for dark mode?
Inversion breaks hierarchy and saturation: pure white text on pure black vibrates, and saturated brand colors that worked on white glow on black. Shifting along a perceptual scale — what this generator does — is why the dark card looks designed rather than filtered.
How does this work with Tailwind?
The v4 export defines the light tokens in @theme and overrides them under .dark — utilities like bg-surface then respond to the class automatically. Pair it with Tailwind's dark: variant for per-element exceptions.