Tailwind CSS Dark Mode
Learn how to implement dark mode in your web applications using Tailwind CSS.
Enabling Dark Mode in Tailwind
Tailwind CSS provides built-in support for dark mode styling. You can choose between class-based or media-query-based dark mode.
Configuration in tailwind.config.js
// tailwind.config.js
module.exports = {
darkMode: 'class', // or 'media' for media query based dark mode
// rest of your configuration
}
Two options for dark mode:
'media'
: Uses theprefers-color-scheme
media query to detect the user's system preference'class'
: Requires manually adding adark
class to the HTML or body element (recommended for toggle functionality)
Using Dark Mode Variants
Once dark mode is enabled, you can use the dark:
variant to apply styles specifically for dark mode.
Basic Dark Mode Example
<div class="bg-white dark:bg-gray-800 text-gray-900 dark:text-white p-6 rounded-lg shadow-md">
<h2 class="text-2xl font-bold mb-4">This is a card</h2>
<p>This card will have a white background with dark text in light mode, and a dark background with light text in dark mode.</p>
</div>
Light Mode
This is a card
White background with dark text in light mode.
Secondary container with lighter background
Dark Mode
This is a card
Dark background with light text in dark mode.
Secondary container with lighter background
Combining Dark Mode with Other Variants
<button class="bg-blue-500 hover:bg-blue-600 dark:bg-blue-600 dark:hover:bg-blue-700 text-white font-bold py-2 px-4 rounded">
Button
</button>
<div class="text-sm md:text-base dark:text-gray-300 md:dark:text-gray-200">
This text combines responsive and dark mode variants.
</div>
Implementing a Dark Mode Toggle
Add a toggle button to let users switch between light and dark mode.
Dark Mode Toggle Button
<!-- Dark mode toggle button -->
<button id="theme-toggle" class="p-2 rounded-full">
<!-- Sun icon (shown in dark mode) -->
<svg id="sun-icon" class="hidden dark:block w-6 h-6 text-yellow-300" fill="currentColor" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" d="M10 2a1 1 0 011 1v1a1 1 0 11-2 0V3a1 1 0 011-1zm4 8a4 4 0 11-8 0 4 4 0 018 0zm-.464 4.95l.707.707a1 1 0 001.414-1.414l-.707-.707a1 1 0 00-1.414 1.414zm2.12-10.607a1 1 0 010 1.414l-.706.707a1 1 0 11-1.414-1.414l.707-.707a1 1 0 011.414 0zM17 11a1 1 0 100-2h-1a1 1 0 100 2h1zm-7 4a1 1 0 011 1v1a1 1 0 11-2 0v-1a1 1 0 011-1zM5.05 6.464A1 1 0 106.465 5.05l-.708-.707a1 1 0 00-1.414 1.414l.707.707zm1.414 8.486l-.707.707a1 1 0 01-1.414-1.414l.707-.707a1 1 0 011.414 1.414zM4 11a1 1 0 100-2H3a1 1 0 000 2h1z" clip-rule="evenodd"></path>
</svg>
<!-- Moon icon (shown in light mode) -->
<svg id="moon-icon" class="block dark:hidden w-6 h-6 text-gray-800" fill="currentColor" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg">
<path d="M17.293 13.293A8 8 0 016.707 2.707a8.001 8.001 0 1010.586 10.586z"></path>
</svg>
</button>
Try the dark mode toggle:
Interactive Demo
This demo lets you toggle between light and dark mode. The toggle only affects this container.
Card Example
This card changes appearance based on the current theme.
Button Examples
JavaScript for Dark Mode Toggle
// JavaScript to toggle dark mode
document.getElementById('theme-toggle').addEventListener('click', function() {
// Toggle dark class on the html element
document.documentElement.classList.toggle('dark');
// Store user preference in localStorage
if (document.documentElement.classList.contains('dark')) {
localStorage.setItem('color-theme', 'dark');
} else {
localStorage.setItem('color-theme', 'light');
}
});
// Check for saved theme preference or system preference
const themePreference = () => {
// Check localStorage
if (localStorage.getItem('color-theme') === 'dark' ||
(!localStorage.getItem('color-theme') && window.matchMedia('(prefers-color-scheme: dark)').matches)) {
document.documentElement.classList.add('dark');
} else {
document.documentElement.classList.remove('dark');
}
};
// Set theme on page load
themePreference();
Dark Mode Color Strategies
Effective color choices for dark mode that maintain accessibility and visual hierarchy.
Common Dark Mode Color Patterns
/* Light mode colors */
.bg-primary { @apply bg-white; }
.bg-secondary { @apply bg-gray-100; }
.bg-accent { @apply bg-blue-500; }
.text-primary { @apply text-gray-900; }
.text-secondary { @apply text-gray-600; }
.border-primary { @apply border-gray-200; }
/* Dark mode colors */
.dark .bg-primary { @apply bg-gray-900; }
.dark .bg-secondary { @apply bg-gray-800; }
.dark .bg-accent { @apply bg-blue-600; }
.dark .text-primary { @apply text-gray-100; }
.dark .text-secondary { @apply text-gray-400; }
.dark .border-primary { @apply border-gray-700; }
Complete Dark Mode Example
<div class="bg-white dark:bg-gray-900 min-h-screen">
<header class="bg-gray-100 dark:bg-gray-800 shadow-sm">
<div class="container mx-auto px-4 py-6">
<h1 class="text-2xl font-bold text-gray-900 dark:text-white">My Application</h1>
</div>
</header>
<main class="container mx-auto px-4 py-8">
<div class="bg-white dark:bg-gray-800 rounded-lg shadow-md p-6 mb-6">
<h2 class="text-xl font-semibold text-gray-900 dark:text-white mb-4">Welcome</h2>
<p class="text-gray-700 dark:text-gray-300">This is an example of a page with dark mode support.</p>
<button class="mt-4 bg-blue-500 hover:bg-blue-600 dark:bg-blue-600 dark:hover:bg-blue-700 text-white font-bold py-2 px-4 rounded">
Get Started
</button>
</div>
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
<div class="bg-white dark:bg-gray-800 rounded-lg shadow-md p-6 border border-gray-200 dark:border-gray-700">
<h3 class="text-lg font-semibold text-gray-900 dark:text-white mb-3">Features</h3>
<ul class="text-gray-700 dark:text-gray-300 space-y-2">
<li>Responsive design</li>
<li>Dark mode support</li>
<li>Accessible components</li>
</ul>
</div>
<div class="bg-white dark:bg-gray-800 rounded-lg shadow-md p-6 border border-gray-200 dark:border-gray-700">
<h3 class="text-lg font-semibold text-gray-900 dark:text-white mb-3">Statistics</h3>
<div class="text-gray-700 dark:text-gray-300">
<p>Users: 1,234</p>
<p>Active: 789</p>
<p>Conversion: 12.3%</p>
</div>
</div>
</div>
</main>
<footer class="bg-gray-100 dark:bg-gray-800 mt-8 py-6">
<div class="container mx-auto px-4 text-gray-600 dark:text-gray-400 text-center">
<p>© 2025 My Application. All rights reserved.</p>
</div>
</footer>
</div>
Accessibility Considerations
Ensuring your dark mode implementation is accessible to all users.
Color Contrast
Maintain sufficient contrast ratios in both light and dark modes:
- Normal text: minimum contrast ratio of 4.5:1
- Large text: minimum contrast ratio of 3:1
Focus Indicators
<!-- Focus indicators that work in both modes -->
<button class="focus:outline-none focus:ring-2 focus:ring-blue-500 dark:focus:ring-blue-400 focus:ring-offset-2 focus:ring-offset-white dark:focus:ring-offset-gray-800">
Accessible Button
</button>
Respecting User Preferences
Always respect the user's system preference when initially loading the page, then allow them to override it if desired.
// Check system preference first, then localStorage
const prefersDarkMode = window.matchMedia('(prefers-color-scheme: dark)').matches;
const storedTheme = localStorage.getItem('color-theme');
if (storedTheme === 'dark' || (!storedTheme && prefersDarkMode)) {
document.documentElement.classList.add('dark');
} else {
document.documentElement.classList.remove('dark');
}
Advanced Dark Mode Techniques
Beyond the basics: advanced techniques for dark mode implementation.
Custom Properties (CSS Variables)
/* Define variables in :root (light mode) */
:root {
--color-bg-primary: 255, 255, 255;
--color-bg-secondary: 243, 244, 246;
--color-text-primary: 31, 41, 55;
--color-text-secondary: 107, 114, 128;
}
/* Override variables in dark mode */
.dark {
--color-bg-primary: 31, 41, 55;
--color-bg-secondary: 17, 24, 39;
--color-text-primary: 243, 244, 246;
--color-text-secondary: 156, 163, 175;
}
/* Use variables with rgb() */
.bg-primary { background-color: rgb(var(--color-bg-primary)); }
.text-primary { color: rgb(var(--color-text-primary)); }
/* Use with opacity */
.bg-primary-90 { background-color: rgba(var(--color-bg-primary), 0.9); }
Dark Mode for Images
<!-- Option 1: Different images for different modes -->
<img src="/light-logo.png" class="block dark:hidden" alt="Logo">
<img src="/dark-logo.png" class="hidden dark:block" alt="Logo">
<!-- Option 2: CSS filters -->
<img src="/logo.png" class="dark:invert" alt="Logo">
Transition Between Modes
<!-- Add transition to specific properties -->
<div class="bg-white text-gray-900 dark:bg-gray-800 dark:text-white transition-colors duration-300">
Content that smoothly transitions between light and dark mode
</div>
<!-- Or add to the html element for global transitions -->
<style>
html.transitioning * {
transition-property: background-color, border-color, color, fill, stroke;
transition-duration: 300ms;
}
</style>
<script>
// Add this before toggling the 'dark' class
document.documentElement.classList.add('transitioning');
// Remove after transition completes
setTimeout(() => {
document.documentElement.classList.remove('transitioning');
}, 300);
</script>
For more Tailwind CSS topics, check out our Fundamentals, Customization, UI Components, and Responsive Design pages.