Getting started
Theme Lab is a free, no-signup visual builder for shadcn/ui themes. Open the Builder and you're ready to go.
- Pick a brand color — type a hex, paste an OKLCH string, or click the color picker.
- Toggle between light and dark mode to preview both.
- Hit Randomize to roll a brand color, or browse the preset library.
- The rotating Custom Vibes row at the top suggests curated themes by mood — click one to apply.
- When you like it, open Export and copy the format you need.
Using the builder
Brand color and sliders
Every token in your theme is derived from a single brand color in OKLCH. The three sliders control:
- Lightness (L) — perceptual brightness from 0 (black) to 1 (white).
- Chroma (C) — saturation. 0 is gray; ~0.3 is roughly the limit of sRGB.
- Hue (H) — angle on the color wheel, 0–360°.
Surface tint and radius
Surface tint bleeds a bit of your brand hue into backgrounds, borders and muted tokens so the whole UI feels of a piece. Radius sets the global corner rounding (the --radius token).
Fonts
Pick a heading and body font from curated pairings (Inter, Geist, Space Grotesk, DM Sans, Manrope, Outfit, Plus Jakarta, Playfair, Instrument Serif, JetBrains Mono, Geist Mono). The fonts are preloaded from Google Fonts on every page.
Contrast checks
The preview panel runs live WCAG contrast checks between foreground/background pairings and flags any that fall below AA (4.5:1 for text, 3:1 for large text).
Live preview
The right side renders real shadcn/ui components — cards, buttons, charts, alerts, forms — using your theme as CSS variables. Every change is instant; there is no rebuild step.
Color space: OKLCH
OKLCH is a modern, perceptually-uniform color space. Unlike HSL or hex, equal numeric steps in OKLCH look like equal steps to the human eye. That means you can rotate the hue of your brand color without the perceived lightness or saturation drifting — which is what makes a derived design system feel consistent.
Theme Lab uses OKLCH natively. We compute everything (primary, accent, muted, border, chart hues, sidebar tokens, ring) from one brand {L, C, H} by applying lightness deltas and chroma clamps so every output stays inside the sRGB gamut while looking harmonious.
Browsers ship native oklch() support in CSS, so the exported index.css uses real OKLCH values — not hex approximations.
Fifth grader speak
Imagine you have a giant box of crayons, but instead of being messy, they are organized in a super-smart way so your eyes never get tricked. That is what OKLCH is!
Here is how it works, using three simple knobs:
1. The Lightness Knob (L) 💡
This controls how bright or dark the color is.
- 0% is pitch black.
- 100% is bright white.
- The magic: In old systems, a "50% bright" yellow looked way brighter than a "50% bright" blue. In OKLCH, if you set the knob to 50%, every color looks equally bright, just like turning a dimmer switch on a lamp.
2. The Color Strength Knob (C) 🎨
This controls how "loud" or "quiet" the color is.
- 0 is gray (no color at all).
- Higher numbers make the color super vivid and strong.
- The magic: You can make a red and a green equally "loud" so one does not steal the show from the other.
3. The Hue Wheel (H) 🎡
This is just the color itself, like spinning a wheel.
- 0° is Red.
- 120° is Green.
- 240° is Blue.
- It works just like a standard color wheel you use in art class.
Why is it better than the old way?
Imagine you are painting a rainbow.
Old Way (RGB/HSL): When you mix colors, sometimes the middle turns muddy or weirdly dark, like a bruise.
OKLCH Way: When you mix colors, the transition is perfectly smooth, like a beautiful sunset. It keeps the brightness steady so your eyes see exactly what you intended.
Export formats
Open the Export dialog in the builder. Five formats are available; copy what fits your stack.
index.css
The canonical shadcn/ui format. CSS custom properties under :root (light) and .dark (dark) — --background, --foreground, --primary, --radius, etc. Paste into your project's global stylesheet.
tailwind.config.ts
A Tailwind v3-style config that maps semantic color names to the CSS variables, plus radius and font-family tokens. Use with Tailwind v3 projects that aren't on the new CSS-first config.
JSON
Raw machine-readable export: OKLCH and hex values for every token, plus radius and font names. Good for piping into your own build pipeline or design tooling.
WordPress theme.json
Schema-validated theme.json (version 3) that registers your palette and typography with the WordPress block editor. Drop into the root of a block theme.
W3C Design Tokens
A .tokens.json in the W3C Design Tokens Community Group format. Import into Figma Token Studio, Style Dictionary, or any tool that speaks the spec.
Integration guide
shadcn/ui (Vite or Next.js)
- Export
index.css. - Paste over your existing
app/globals.cssorsrc/index.css— keep the@tailwinddirectives at the top. - Done. Components automatically pick up the new variables.
Tailwind v3
Use both exports together: index.css for the variables and tailwind.config.ts so utilities like bg-primary resolve correctly.
Tailwind v4
Tailwind v4 is CSS-first — you only need index.css. Paste it into your stylesheet; the @theme block in v4 reads CSS variables directly.
WordPress block themes
Place the exported theme.json at the root of your block theme (next to style.css). The palette appears in the editor's color picker on next load.
Figma (Token Studio)
In Token Studio, choose Import → Single file (JSON) and select your .tokens.json. Tokens land in a new set you can apply to your library.
Highly technical nerd speak
OKLCH math
OKLCH is the polar form of Oklab (Björn Ottosson, 2020). L is approximately CIE Lstar but corrected for predictability across hues; C is the Euclidean distance √(a² + b²) in Oklab; H is atan2(b, a) in degrees. Conversion to sRGB goes Oklab → linear LMS (cube of the LMS components) → linear sRGB via a fixed 3×3 matrix → gamma-corrected sRGB.
Gamut mapping
Not every OKLCH triple has an sRGB representation — high chroma at extreme lightness falls out of gamut. Theme Lab clamps chroma while preserving L and H (the perceptually-preferred strategy from the CSS Color 4 spec) so derived tokens never round to garbage when serialized.
Token derivation
From one brand {L, C, H} we compute:
- Foreground/background: L pinned near 0.98 / 0.15 with a sliver of brand chroma for the surface tint.
- Muted / accent / border: lightness deltas off the surface, chroma scaled by the tint factor.
- Primary foreground: chosen by WCAG contrast against primary — black or white, whichever wins.
- Chart tokens: brand hue plus rotations of 30°, 60°, 120°, 200° at matched L/C — gives 5 distinguishable series that share a family.
- Sidebar tokens: a parallel scale derived from the surface, slightly cooler/darker.
Contrast
WCAG 2.1 contrast ratio is (L1 + 0.05) / (L2 + 0.05) where L is relative luminance from linearized sRGB. We compute it on every render for foreground/background pairs and flag anything under 4.5:1.
Why native oklch() over color-mix
color-mix() is great for runtime tweaks but loses fidelity when chained. Emitting concrete oklch(L C H) values keeps the design system reproducible — the file you export is exactly the file the browser parses.
P3 and beyond
OKLCH carries unambiguously to wide-gamut displays. If you ever opt out of the sRGB clamp, the same theme will render with richer chroma on P3 hardware without any extra work.
FAQ
Is it really free?
Yes. No account, no paywall, no usage limits.
Do you store my themes?
Themes live in your browser's local storage. We don't send them anywhere unless you explicitly share or export them.
Can I import an existing theme?
Not yet — today the builder is brand-color-first. Round-tripping from an existing index.css is on the roadmap.
Does it work with Tailwind v4?
Yes. Use the index.css export; v4's CSS-first config reads the variables directly.
Can I use the themes commercially?
Yes. Themes you build are yours — ship them in any project, commercial or otherwise.
Still stuck?
Open the builder and use the floating feedback button in the corner to send a question.