OpenTailwindOpenTailwindOpenTailwindOpenTailwindv0.0.1
BlocksTemplates
How to Add Dark Mode to Any Tailwind CSS Website (The Right Way)
BlogHow to Add Dark Mode to Any Tailwind CSS Website (The Right Way)
TutorialApril 7, 2026·9 min read

How to Add Dark Mode to Any Tailwind CSS Website (The Right Way)

The complete guide to implementing dark mode with Tailwind CSS. Covers class strategy, system preferences, persistence, and the common pitfalls that make text invisible.

Dark mode isn't optional anymore — users expect it. Tailwind CSS makes it straightforward with the dark: prefix, but there are pitfalls that catch even experienced developers. Here's how to do it right.

The Basics: How dark: Works

Tailwind's dark mode works by adding a dark class to the <html> element. Any class prefixed with dark: only applies when that class is present.

<!-- Light mode: white bg, dark text -->
<!-- Dark mode: dark bg, light text -->
<div class="bg-white dark:bg-neutral-950">
  <h1 class="text-neutral-900 dark:text-white">Hello</h1>
  <p class="text-neutral-600 dark:text-neutral-400">World</p>
</div>

The #1 Mistake: Dark-Only Styling

The most common bug: writing styles that only work in dark mode.

<!-- ❌ WRONG: This is invisible in light mode -->
<section class="bg-neutral-950">
  <h1 class="text-white">Can't see this in light mode</h1>
</section>

<!-- ✅ RIGHT: Works in both modes -->
<section class="bg-white dark:bg-neutral-950">
  <h1 class="text-neutral-900 dark:text-white">Visible everywhere</h1>
</section>

Every element needs both a light mode default and a dark mode variant. No exceptions.

Color Mapping Cheat Sheet

Element Light Mode Dark Mode
Page backgroundbg-whitedark:bg-neutral-950
Card backgroundbg-neutral-50dark:bg-neutral-900
Primary texttext-neutral-900dark:text-white
Body texttext-neutral-600dark:text-neutral-400
Muted texttext-neutral-500dark:text-neutral-400
Bordersborder-neutral-200dark:border-neutral-800
Accent texttext-indigo-600dark:text-indigo-400
Input backgroundbg-whitedark:bg-neutral-900

Strategy 1: Class-Based Toggle (Recommended)

Add/remove the dark class on <html> based on user preference. This gives users control.

// Toggle dark mode
document.documentElement.classList.toggle('dark');

// Check current mode
const isDark = document.documentElement.classList.contains('dark');

// Persist preference
localStorage.setItem('theme', isDark ? 'dark' : 'light');

Strategy 2: System Preference

Respect the user's OS-level dark mode setting automatically.

// Check system preference
const prefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches;

// Apply on load
if (prefersDark) {
  document.documentElement.classList.add('dark');
}

// Listen for changes
window.matchMedia('(prefers-color-scheme: dark)')
  .addEventListener('change', (e) => {
    document.documentElement.classList.toggle('dark', e.matches);
  });

Strategy 3: Both (Best UX)

Default to system preference, but let users override. Store the override in localStorage.

// On page load
const stored = localStorage.getItem('theme');
if (stored) {
  document.documentElement.classList.toggle('dark', stored === 'dark');
} else {
  // Fall back to system preference
  const prefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches;
  document.documentElement.classList.toggle('dark', prefersDark);
}

Common Pitfalls

  • White text on white background — Always pair text-white with a dark background or use text-neutral-900 dark:text-white
  • Forgetting borders — border-neutral-200 dark:border-neutral-800 is easy to miss
  • Images without adaptation — Consider dark:opacity-80 or dark:brightness-90 for images that are too bright in dark mode
  • Flash of wrong theme — Load the theme preference in a <script> in <head> (before render) to prevent the flash

💡 Pro tip: Bookmark the color mapping table above. You'll reference it on every project. Or better yet, browse OpenTailwind's blocks — every one has proper light/dark mode support you can learn from.

Browse 1,761 free Tailwind CSS blocks

Production-ready UI sections for your next project. Free forever, open source.

Browse BlocksTemplates
← Previous article

How to Build a SaaS Landing Page with Tailwind CSS in Under 30 Minutes

Next article →

How to Build a Pricing Page with Tailwind CSS (Monthly/Yearly Toggle)

OpenTailwindOpenTailwindv0.0.1
AboutTermsCookies
bylindo.ai