Dynamic Theme Switching with Tailwind CSS
Build a multi-theme system in Tailwind CSS that lets users switch between color themes at runtime.
Beyond Dark Mode: Multi-Theme Systems
Most sites only toggle light and dark. But with CSS custom properties and Tailwind, you can support unlimited themes: seasonal palettes, brand sub-themes, or user-personalized colors, all without rebuilding CSS.
Defining Multiple Themes
@layer base {
:root, .theme-default {
--color-primary: 59 130 246;
--color-surface: 255 255 255;
--color-text: 15 23 42;
}
.theme-forest {
--color-primary: 22 163 74;
--color-surface: 240 253 244;
--color-text: 20 83 45;
}
.theme-sunset {
--color-primary: 234 88 12;
--color-surface: 255 247 237;
--color-text: 124 45 18;
}
.theme-ocean {
--color-primary: 6 182 212;
--color-surface: 236 254 255;
--color-text: 21 94 117;
}
}Theme Switcher Component
function ThemeSwitcher() {
const themes = ['default', 'forest', 'sunset', 'ocean'];
function setTheme(name) {
const root = document.documentElement;
themes.forEach(t => root.classList.remove(`theme-${t}`));
root.classList.add(`theme-${name}`);
localStorage.setItem('theme', name);
}
return (
<div className="flex gap-2">
{themes.map(t => (
<button key={t} onClick={() => setTheme(t)}
className="w-8 h-8 rounded-full bg-primary border-2 border-white shadow" />
))}
</div>
);
}Architecture Tips
- Store all theme-dependent colors as CSS variables, never as hardcoded Tailwind classes
- Use semantic names (primary, surface, text) instead of descriptive names (blue, white)
- Load saved theme before first paint to prevent flash
- Each theme should define all required variables to avoid missing values
- Test contrast ratios for every theme to maintain accessibility
Frequently Asked Questions
How many themes can I support?
There is no practical limit. Each theme is a CSS class with variable overrides. Since variables are inherited, only the overridden values take up space.
Does multi-theme increase CSS bundle size?
Minimally. Each theme adds only the CSS variable declarations (a few hundred bytes). The Tailwind utility classes themselves are shared across all themes.
How do I prevent a flash of wrong theme on load?
Add a blocking script in the head element that reads localStorage and applies the theme class before the browser paints. This avoids any visible theme flash.
Try Our Color Tools
50+ free tools for Tailwind CSS developers. No signup required.
Explore Tools