Dark Mode
Learn how to implement dark mode in Tailwind CSS with the dark: variant, and understand class-based versus media-based dark mode strategies.
Introduction
Dark mode has become a standard expectation for modern web applications, both for aesthetics and to reduce eye strain in low-light environments. Tailwind CSS makes dark mode straightforward with the dark: variant, which applies a utility class only when dark mode is active.
- How the dark: variant works.
- The difference between media-based and class-based dark mode.
- How to build a manual light/dark theme toggle.
- How to choose the right strategy for your project.
The dark: Variant
Prefix any utility with dark: to apply it only in dark mode. It is most commonly used for background colors, text colors, and border colors, letting a single element look correct in both light and dark themes.
<div class="bg-white text-slate-900 dark:bg-slate-900 dark:text-white p-6 rounded-lg"> This card adapts its colors based on the active theme.</div>Click Run to see what this code prints.
Media Strategy
By default, Tailwind uses the media strategy, which relies on the prefers-color-scheme CSS media feature. This means dark: styles automatically activate whenever the user's operating system is set to dark mode, with no JavaScript required. It is simple to set up, but the user cannot override it independently of their OS setting.
// tailwind.config.jsmodule.exports = { darkMode: 'media', // default behavior // ...};Class Strategy
Setting darkMode to 'class' switches Tailwind to look for a dark class on a parent element (usually <html>) instead of the OS setting. This lets you build a manual toggle button that lets users choose light or dark mode themselves, independent of their system preference.
// tailwind.config.jsmodule.exports = { darkMode: 'class', // ...};<html class="dark"> <body class="bg-white dark:bg-slate-900"> <!-- dark: utilities now apply because the html tag has the dark class --> </body></html>Building a Theme Toggle
With the class strategy, a theme toggle simply adds or removes the dark class on the document element, typically saving the user's choice to localStorage so it persists across visits.
function toggleTheme() { const html = document.documentElement; const isDark = html.classList.toggle('dark'); localStorage.setItem('theme', isDark ? 'dark' : 'light');}
// On page load, restore the saved preferenceif (localStorage.getItem('theme') === 'dark') { document.documentElement.classList.add('dark');}Click Run to see what this code prints.
Choosing a Strategy
| Strategy | Best For |
|---|---|
| media | Simple sites that only need to follow the OS setting |
| class | Apps that need a user-facing light/dark toggle |
Common Mistakes
- Forgetting to set darkMode: 'class' in tailwind.config.js before building a manual toggle — without it, dark: still only follows the OS setting.
- Only adding dark: styles to backgrounds and forgetting text, border, and shadow colors, which can leave low-contrast or invisible content.
- Not persisting the user's theme choice, forcing them to re-select it on every visit.
- Applying the dark class after the page has already rendered, causing a visible flash of the wrong theme.
- Hardcoding colors with arbitrary hex values instead of Tailwind's color scale, making dark: overrides inconsistent.
Best Practices
- Use the class strategy whenever you want to offer users a manual toggle.
- Apply the saved theme class before the page paints (in an inline script) to avoid a flash of incorrect theme.
- Check contrast carefully in dark mode — colors that work on white backgrounds can be hard to read on dark ones.
- Test every component in both themes, not just the overall page background.
- Keep a consistent light/dark color pairing convention across the whole app, such as always pairing slate-900 with white.
Frequently Asked Questions
You configure one strategy globally in tailwind.config.js, but many apps use the class strategy and default the initial class based on prefers-color-scheme, effectively getting the best of both.
The media strategy requires no JavaScript at all. The class strategy needs a small amount of JavaScript to toggle the class and persist the preference.
Yes, variants can be stacked, for example dark:hover:bg-slate-700, which only applies on hover while dark mode is active.
Key Takeaways
- The dark: variant applies a utility only when dark mode is active.
- The media strategy follows the operating system's color scheme automatically.
- The class strategy lets you build a manual light/dark toggle by adding or removing a class on <html>.
- Persist the user's theme choice in localStorage for a consistent experience.
- Apply dark: styles to text, borders, and shadows, not just backgrounds.
Summary
Dark mode support in Tailwind is just another variant, no different in spirit from hover: or md:, which makes it easy to weave into components as you build them rather than bolting it on afterward. Next, you will learn how to control borders and rounded corners to give your components clean, polished edges.