The CSS Variable Theme Generator builds a complete set of design tokens from a
single primary color and a chosen type scale, then emits them as a :root block
of CSS custom properties. It is a fast way to bootstrap a coherent theme without
hand-writing dozens of variables.
How it works
Colors start from your primary’s HSL value. The accent is its complementary hue (180 degrees away), while surface, text, and border tokens reuse the primary hue at low saturation so neutrals share the same undertone. Typography is a modular scale around your base size:
accent = hslToHex((hue + 180) mod 360, sat, light)
surface/text = same hue, low saturation, fixed light/dark lightness
text-step(i) = base × ratio^(i − 1) // "base" step = your base size
spacing = 0.25, 0.5, 1, 1.5, 2, 3 rem (xs ... 2xl)
Radius and shadow tokens are sensible fixed defaults you can tune after pasting.
What the output looks like
:root {
--color-primary: #3b82f6;
--color-primary-hover: #2563eb;
--color-accent: #f6a23b;
--color-surface: #f0f4ff;
--color-text: #1a1f3c;
--color-border: #d0d8f0;
--space-xs: 0.25rem;
--space-sm: 0.5rem;
--space-md: 1rem;
--space-lg: 1.5rem;
--space-xl: 2rem;
--space-2xl: 3rem;
--text-sm: 0.75rem;
--text-base: 1rem;
--text-lg: 1.25rem;
--text-xl: 1.5625rem;
--text-2xl: 1.953rem;
--text-3xl: 2.441rem;
--radius-sm: 0.25rem;
--radius-md: 0.5rem;
--radius-lg: 1rem;
--shadow-sm: 0 1px 2px rgba(0,0,0,0.05);
--shadow-md: 0 4px 6px rgba(0,0,0,0.1);
--shadow-lg: 0 10px 15px rgba(0,0,0,0.15);
}
Tips and notes
Pick a saturated primary in the 40–55% lightness band. Too light and the hover state won’t be visible; too dark and the tinted neutrals become muddy. A mid-range blue, green, or purple works well as a starting point.
Font sizes are in rem. This means they scale automatically when a user changes their browser font-size preference — an accessibility benefit that pixel-based sizes do not provide.
To support dark mode, copy the :root block into a prefers-color-scheme: dark media query, then flip the surface and text lightness values: make surface dark and text light. Because the variable names stay identical, no component markup needs to change — only the token values switch.
@media (prefers-color-scheme: dark) {
:root {
--color-surface: #1a1f3c;
--color-text: #f0f4ff;
--color-border: #2d3560;
}
}
Use the tokens consistently in components. Referencing var(--space-md) throughout your CSS means a single change to the token instantly resizes all the affected spacing across the whole project — the core value of a token-based system.
Adapting the output to a Tailwind project
If you are using Tailwind CSS, you can bridge the generated tokens into your config rather than using them in raw CSS. In tailwind.config.js, extend the theme with your token values:
module.exports = {
theme: {
extend: {
colors: {
primary: 'var(--color-primary)',
accent: 'var(--color-accent)',
surface: 'var(--color-surface)',
},
spacing: {
xs: 'var(--space-xs)',
sm: 'var(--space-sm)',
md: 'var(--space-md)',
},
},
},
}
This means you get both the Tailwind utility-class workflow (bg-primary, p-md) and the CSS custom property system for any component that reads the tokens directly.
Naming conventions and maintenance
The generated names follow a predictable pattern: --category-scale. This makes them scannable (--space-* for all spacing, --text-* for all type) and easy to search in a codebase. As a project grows, add variants by appending suffixes (--color-primary-light, --color-primary-dark) without breaking existing references to --color-primary.