Tailwind CSS Dark Mode Guide
Complete reference for implementing dark mode in Tailwind CSS.
Learn configuration, modifiers, toggles, and component patterns.
Setup & Configuration
Enabling Dark Mode
Tailwind CSS supports dark mode out of the box. By default, it uses the prefers-color-scheme CSS media query.
Media Strategy (Default)
// tailwind.config.js
module.exports = {
darkMode: 'media',
// ...
}Pros:
- Zero JavaScript required
- Respects system preference automatically
- Works immediately on page load
Cons:
- No user toggle without JavaScript
- Cannot override system preference
Class Strategy
// tailwind.config.js
module.exports = {
darkMode: 'class',
// ...
}Pros:
- Full control over dark mode
- Can persist user preference
- Works with any toggle mechanism
Cons:
- Requires JavaScript for toggling
- May flash on initial load if not handled
Tailwind v4 Note: In Tailwind v4, dark mode uses the media strategy by default. To use the class strategy, add @variant dark (&.dark) to your CSS.
Using the dark: Modifier
Basic Usage
Prefix any utility class with dark: to apply it only in dark mode.
<div class="bg-white dark:bg-gray-900">
<h1 class="text-gray-900 dark:text-white">Hello World</h1>
<p class="text-gray-600 dark:text-gray-400">Welcome to dark mode!</p>
</div>Combining with Other Modifiers
Stack dark: with hover, focus, and responsive modifiers.
<!-- Hover states -->
<button class="bg-blue-500 hover:bg-blue-600 dark:bg-blue-600 dark:hover:bg-blue-700">
Click me
</button>
<!-- Focus states -->
<input class="border-gray-300 focus:border-blue-500
dark:border-gray-600 dark:focus:border-blue-400" />
<!-- Responsive + dark -->
<div class="bg-white md:bg-gray-50 dark:bg-gray-900 dark:md:bg-gray-800">
Responsive dark mode
</div>Common Dark Mode Patterns
Background
bg-white dark:bg-gray-900Text Color
text-gray-900 dark:text-gray-100Border
border-gray-200 dark:border-gray-700Hover State
hover:bg-gray-100 dark:hover:bg-gray-800Common Utility Pairs
Reference table of commonly paired light and dark mode utilities. Click any row to copy both classes.
| Purpose | Light Mode | Dark Mode | |
|---|---|---|---|
| Background | bg-white | dark:bg-gray-900 | |
| Surface | bg-gray-50 | dark:bg-gray-800 | |
| Elevated | bg-gray-100 | dark:bg-gray-700 | |
| Primary text | text-gray-900 | dark:text-gray-100 | |
| Secondary text | text-gray-700 | dark:text-gray-300 | |
| Muted text | text-gray-500 | dark:text-gray-400 | |
| Border | border-gray-200 | dark:border-gray-700 | |
| Border strong | border-gray-300 | dark:border-gray-600 | |
| Divider | divide-gray-200 | dark:divide-gray-700 | |
| Ring | ring-gray-300 | dark:ring-gray-600 | |
| Placeholder | placeholder-gray-400 | dark:placeholder-gray-500 | |
| Shadow | shadow-sm | dark:shadow-gray-900/20 |
JavaScript Toggle
Basic Toggle Function
When using darkMode: 'class', toggle the dark class on the <html> element.
// Toggle dark mode
function toggleDarkMode() {
document.documentElement.classList.toggle('dark');
}
// Set dark mode explicitly
function setDarkMode(isDark) {
if (isDark) {
document.documentElement.classList.add('dark');
} else {
document.documentElement.classList.remove('dark');
}
}
// Check current state
function isDarkMode() {
return document.documentElement.classList.contains('dark');
}React Toggle Hook
import { useState, useEffect } from 'react';
function useDarkMode() {
const [isDark, setIsDark] = useState(false);
useEffect(() => {
// Check initial preference
const isDarkMode = document.documentElement.classList.contains('dark');
setIsDark(isDarkMode);
}, []);
const toggle = () => {
setIsDark(!isDark);
document.documentElement.classList.toggle('dark');
};
return { isDark, toggle };
}
// Usage
function ThemeToggle() {
const { isDark, toggle } = useDarkMode();
return (
<button onClick={toggle}>
{isDark ? '🌙' : '☀️'}
</button>
);
}Persisting User Preference
localStorage Implementation
Save the user's preference to localStorage and restore it on page load.
// Save preference
function setTheme(theme) {
localStorage.setItem('theme', theme);
if (theme === 'dark') {
document.documentElement.classList.add('dark');
} else {
document.documentElement.classList.remove('dark');
}
}
// Load preference on page load
function initTheme() {
const savedTheme = localStorage.getItem('theme');
if (savedTheme) {
setTheme(savedTheme);
} else if (window.matchMedia('(prefers-color-scheme: dark)').matches) {
// Fallback to system preference
setTheme('dark');
}
}
// Call on page load
initTheme();Prevent Flash of Wrong Theme
Add this script in the <head> to prevent the flash of light mode before JavaScript loads.
<head>
<!-- Add this script BEFORE any stylesheets -->
<script>
if (localStorage.theme === 'dark' ||
(!('theme' in localStorage) &&
window.matchMedia('(prefers-color-scheme: dark)').matches)) {
document.documentElement.classList.add('dark');
} else {
document.documentElement.classList.remove('dark');
}
</script>
<!-- Your stylesheets -->
<link rel="stylesheet" href="/styles.css" />
</head>Three-way Toggle (Light / Dark / System)
function setTheme(theme) {
if (theme === 'system') {
localStorage.removeItem('theme');
const prefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches;
document.documentElement.classList.toggle('dark', prefersDark);
} else {
localStorage.setItem('theme', theme);
document.documentElement.classList.toggle('dark', theme === 'dark');
}
}
// Listen for system preference changes
window.matchMedia('(prefers-color-scheme: dark)')
.addEventListener('change', (e) => {
if (!localStorage.getItem('theme')) {
document.documentElement.classList.toggle('dark', e.matches);
}
});Component Examples
Card Component
Card Title
This is a card component that adapts to dark mode using Tailwind utilities.
<div class="bg-white dark:bg-gray-800 border border-gray-200 dark:border-gray-700 rounded-lg p-4">
<h4 class="text-gray-900 dark:text-white font-semibold mb-2">Card Title</h4>
<p class="text-gray-600 dark:text-gray-400 text-sm">Card description...</p>
<button class="mt-4 px-4 py-2 bg-blue-500 dark:bg-blue-600
hover:bg-blue-600 dark:hover:bg-blue-700
text-white rounded-lg">
Action
</button>
</div>Button Component
<!-- Primary Button -->
<button class="bg-blue-500 dark:bg-blue-600
hover:bg-blue-600 dark:hover:bg-blue-700
text-white px-4 py-2 rounded-lg">
Primary
</button>
<!-- Secondary Button -->
<button class="border border-gray-300 dark:border-gray-600
text-gray-700 dark:text-gray-300
hover:bg-gray-100 dark:hover:bg-gray-800
px-4 py-2 rounded-lg">
Secondary
</button>
<!-- Ghost Button -->
<button class="text-gray-600 dark:text-gray-400
hover:text-gray-900 dark:hover:text-gray-200
hover:bg-gray-100 dark:hover:bg-gray-800
px-4 py-2 rounded-lg">
Ghost
</button>Input Component
<label class="block text-sm font-medium text-gray-700 dark:text-gray-200 mb-2">
Email Address
</label>
<input
type="email"
placeholder="you@example.com"
class="w-full px-4 py-2 rounded-lg border
bg-white dark:bg-gray-800
border-gray-300 dark:border-gray-600
text-gray-900 dark:text-white
placeholder-gray-400 dark:placeholder-gray-500
focus:border-blue-500 dark:focus:border-blue-400
outline-none"
/>Navigation Component
<nav class="bg-white dark:bg-gray-900 border-b border-gray-100 dark:border-gray-800 px-6 py-4">
<div class="flex items-center justify-between">
<span class="font-bold text-lg text-gray-900 dark:text-white">Logo</span>
<div class="flex gap-6">
<a href="#" class="text-sm font-medium
text-gray-600 dark:text-gray-300
hover:text-gray-900 dark:hover:text-white">
Home
</a>
<a href="#" class="text-sm font-medium
text-gray-600 dark:text-gray-300
hover:text-gray-900 dark:hover:text-white">
About
</a>
</div>
</div>
</nav>Dark Mode Tips
Start with semantic colors: Use bg-white dark:bg-gray-900 for backgrounds and layer up from there.
Test both modes: Always test your UI in both light and dark mode during development.
Consider contrast: Ensure text has sufficient contrast against backgrounds in both modes.
Use opacity for subtle variations: text-white/80 works great for secondary text in dark mode.
Explore more Tailwind tools
Tailwind Grid Generator
Create grid layouts visually
Tailwind Flexbox Generator
Create flex layouts visually
Tailwind Gradient Generator
Create custom gradients
Tailwind Text Gradient
Gradient text effects
Tailwind Gradients Collection
275+ ready-to-use gradients
Tailwind Colors
Complete 240+ color palette
Tailwind Box Shadow Generator
Design multi-layer shadows
Tailwind Text Shadow
Add depth to text with shadows
Tailwind Filter Generator
Apply blur, brightness & more
Tailwind Transform Generator
Rotate, scale & translate elements
Tailwind Animation Generator
Create built-in & custom animations
Tailwind Transition Generator
Smooth hover transitions
Tailwind Config Generator
Generate your config file
Tailwind Input Generator
Design form inputs visually
Tailwind Class Sorter
Organize classes in order
Flexbox Cheatsheet
All flex utilities visualized
Overflow Cheatsheet
Control content overflow
