Tailwind CSS Guide
Tailwind CSS Dark Mode
Add a working dark mode toggle to any project with localStorage persistence.
Last updated: October 2026 ยท Tested on Tailwind v4.0
Quick answer: In Tailwind v4, enable dark mode with @custom-variant dark (&:where(.dark, .dark *)); in your CSS. Then use dark: prefixes on any utility: bg-white dark:bg-slate-900. Toggle the .dark class on the <html> element with JavaScript.
Enable Dark Mode in Tailwind v4
Add this line to your main CSS file, right after the Tailwind import:
@import "tailwindcss";
@custom-variant dark (&:where(.dark, .dark *));
This tells Tailwind that the dark: prefix should activate when the .dark class is present on any ancestor element.
๐ก Tailwind v3 users: Set darkMode: 'class' in your tailwind.config.js. In v4, the config file is gone โ you do it in CSS.
Use Dark Mode Variants
Add the dark: prefix to any utility class to give it a different style in dark mode:
<div class="bg-white dark:bg-slate-900 text-slate-900 dark:text-white">
<h1 class="text-3xl font-bold">Hello</h1>
<p class="text-slate-600 dark:text-slate-400">This text adapts.</p>
</div>
You only need to override the properties that change. The light mode values are the defaults.
Prevent Flash on Page Load
Add this small inline script in the <head> of your HTML, before any CSS loads:
<script>
(function() {
const stored = localStorage.getItem('theme');
const prefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches;
if (stored === 'dark' || (!stored && prefersDark)) {
document.documentElement.classList.add('dark');
}
})();
</script>
Why this matters: Without this script, users see a flash of the light theme before the dark theme applies. It's jarring and looks unprofessional.
Build the Toggle Button
Here's a simple dark mode toggle for React:
import { useEffect, useState } from 'react';
export function DarkModeToggle() {
const [isDark, setIsDark] = useState(false);
useEffect(() => {
setIsDark(document.documentElement.classList.contains('dark'));
}, []);
function toggle() {
const next = !isDark;
setIsDark(next);
document.documentElement.classList.toggle('dark', next);
localStorage.setItem('theme', next ? 'dark' : 'light');
}
return (
<button onClick={toggle} aria-label="Toggle dark mode">
{isDark ? 'โ๏ธ' : '๐'}
</button>
);
}
Vanilla JavaScript Version
If you're not using a framework, here's the plain JS toggle:
<button id="theme-toggle" aria-label="Toggle dark mode">๐</button>
<script>
const btn = document.getElementById('theme-toggle');
btn.addEventListener('click', () => {
const isDark = document.documentElement.classList.toggle('dark');
localStorage.setItem('theme', isDark ? 'dark' : 'light');
btn.textContent = isDark ? 'โ๏ธ' : '๐';
});
</script>
Three-State Toggle (System / Light / Dark)
For the best UX, let users choose "System" as well as explicit light or dark:
type Theme = 'system' | 'light' | 'dark';
function applyTheme(theme: Theme) {
const html = document.documentElement;
html.classList.remove('dark');
if (theme === 'dark') {
html.classList.add('dark');
} else if (theme === 'system') {
const prefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches;
if (prefersDark) html.classList.add('dark');
}
localStorage.setItem('theme', theme);
}
This gives users full control while defaulting to their OS preference.
๐ก๏ธ Best Practices
- Use the
classstrategy, notmedia, if you want a toggle button. - Always add the inline script in
<head>to prevent the flash. - Store user choice in
localStorage, not cookies. - Respect
prefers-color-schemeon first visit. - Test all your pages with dark mode on โ some colors become invisible.
- Use semantic color scales:
slate-900for dark backgrounds,slate-100for light backgrounds.
Accessibility tip: Never rely on color alone to convey information. Ensure sufficient contrast in both light and dark modes.
โ Frequently Asked Questions
How do I enable dark mode in Tailwind CSS?
In Tailwind v4, add @custom-variant dark (&:where(.dark, .dark *)); to your CSS file. Then use the dark: prefix on any utility class.
What is the difference between class and media dark mode strategies?
The 'media' strategy follows the user's operating system preference automatically. The 'class' strategy lets you toggle dark mode manually with JavaScript. Most sites use 'class' for a toggle button.
How do I persist dark mode across page reloads?
Save the user's preference in localStorage. On page load, read the value and apply the dark class before the page renders to avoid a flash of the wrong theme.
How do I avoid the flash of light mode on page load?
Add a small inline script in the head of your HTML that reads localStorage and applies the dark class before the page renders. This prevents the flash.
Does dark mode affect SEO?
No, dark mode is purely a UX feature. It does not affect SEO directly. However, it can improve user engagement (dwell time) which is a positive ranking signal.