Dark Mode in Tailwind: A Step-by-Step Guide

By Maulik Paghdal

29 Jul, 2024

•  10 minutes to Read

Dark Mode in Tailwind: A Step-by-Step Guide

Introduction

Dark mode is no longer just a design trend—it has become an essential feature for modern web applications. Many users prefer dark mode for better readability, reduced eye strain, and improved battery efficiency, especially on OLED and AMOLED screens.

With Tailwind CSS, implementing dark mode is straightforward, thanks to its built-in dark: utility. This guide will walk you through the setup, customization, and best practices for using dark mode in Tailwind CSS, ensuring a smooth user experience.

Why Use Dark Mode?

Dark mode is more than just an aesthetic choice; it provides several practical benefits:

  • 🏥 Better Accessibility: Reduces eye strain in low-light environments, making reading easier.
  • 🔋 Energy Efficiency: Saves battery life on devices with OLED and AMOLED displays by using less power for dark pixels.
  • 🎨 Aesthetic Appeal: Gives your application a sleek, modern look that users love.
  • ⚡ User Preference: Many users enable dark mode by default in their system settings, so supporting it improves user satisfaction.

Setting Up Tailwind CSS

Before implementing dark mode, ensure that Tailwind CSS is properly installed in your project. If you haven't already set up Tailwind, follow these steps.

Step 1: Install Tailwind CSS

Use npm to install Tailwind CSS and its required dependencies:

npm install -D tailwindcss postcss autoprefixer
npx tailwindcss init

This command will generate a tailwind.config.js file, which we’ll modify in the next step.

Step 2: Configure Tailwind for Dark Mode

To enable dark mode in Tailwind CSS, open your tailwind.config.js file and update it as follows:

module.exports = {
  darkMode: 'class', // Enables class-based dark mode (alternative: 'media')
  content: ['./src/**/*.{html,js}'], // Adjust this path based on your project structure
  theme: {
    extend: {},
  },
  plugins: [],
};

Dark Mode Strategies in Tailwind CSS

Tailwind CSS provides a streamlined and versatile approach to implementing dark mode, empowering developers to cater to diverse user preferences with minimal configuration. Whether you want to give users manual control over their theme or seamlessly align with their system settings, Tailwind offers two distinct strategies: class-based and media query-based dark mode.

Each method has its own strengths, workflows, and ideal use cases. In this section, we’ll dive into both approaches, exploring how they work, when to use them, and how to set them up in your project. For the purposes of this guide, we’ll focus on the class-based approach to demonstrate a hands-on, user-controlled dark mode experience—but we’ll ensure you understand both options thoroughly.

1. Class-Based Dark Mode (darkMode: 'class')

The class-based strategy (darkMode: 'class') gives you explicit control over when dark mode is activated by relying on the addition or removal of a dark class on a parent element—typically the <html> or <body> tag. This approach is perfect for scenarios where you want to offer users a theme switcher or toggle button, allowing them to choose between light and dark modes based on their preference or context (e.g., time of day or lighting conditions).

How It Works:

When darkMode is set to 'class' in your tailwind.config.js, Tailwind activates dark mode styles only when the dark class is present in the DOM hierarchy. You define dark-specific styles using the dark: prefix (e.g., dark:bg-gray-900), and these styles remain dormant until the dark class triggers them. This manual toggling mechanism requires a bit of JavaScript to add or remove the class dynamically, but it offers unparalleled flexibility.

Configuration

To enable class-based dark mode, update your tailwind.config.js like this:

module.exports = {
  darkMode: 'class', // Enables class-based dark mode
  content: ['./src/**/*.{html,js,ts,jsx,tsx}'], // Adjust paths to your files
  theme: {
    extend: {},
  },
  plugins: [],
};

Example Implementation

Here’s a basic setup to toggle dark mode manually:

<!DOCTYPE html>
<html lang="en" class="light"> <!-- Default to light mode -->
<head>
  <meta charset="UTF-8">
  <title>Class-Based Dark Mode</title>
  <link href="/path/to/tailwind.css" rel="stylesheet">
</head>
<body class="bg-white dark:bg-gray-900 text-gray-900 dark:text-white transition-colors duration-300">
  <button id="toggle" class="px-4 py-2 bg-gray-200 dark:bg-gray-700 rounded">
    Toggle Theme
  </button>
  <h1 class="text-2xl mt-4">Hello, Dark Mode!</h1>

  <script>
    const toggle = document.getElementById('toggle');
    const html = document.documentElement;
    toggle.addEventListener('click', () => {
      html.classList.toggle('dark');
      // Optional: Save preference
      localStorage.setItem('theme', html.classList.contains('dark') ? 'dark' : 'light');
    });
    // Load saved preference
    if (localStorage.getItem('theme') === 'dark') html.classList.add('dark');
  </script>
</body>
</html>
  • classList.toggle('dark'): Adds or removes the dark class on click.
  • transition-colors: Smooths the switch between themes for a polished UX.
  • localStorage: Persists the user’s choice across sessions.

Use Cases

  • Theme Switchers: Ideal for applications where users expect a toggle (e.g., dashboards, blogs, or e-commerce sites).
  • Custom Logic: Perfect when you need to tie dark mode to specific conditions (e.g., time-based themes or user account settings).
  • Full Control: Suits projects where automatic system detection isn’t desired or supported.

Advantages

  • Granular control over theme switching.
  • Easy integration with interactive UI elements like buttons or dropdowns.
  • No reliance on external factors like OS settings.

Considerations

  • Requires JavaScript for toggling, adding a slight overhead.
  • You’ll need to design a UI for users to interact with the toggle.

2. Media Query-Based Dark Mode (darkMode: 'media')

The media query-based strategy (darkMode: 'media') takes a hands-off approach by automatically applying dark mode based on the user’s system preferences. If a user has enabled dark mode in their operating system (e.g., via macOS System Settings or Windows Display Settings), your website or application will mirror that choice using the prefers-color-scheme media query. This method is ideal for delivering a seamless, low-maintenance experience that respects user defaults without requiring manual intervention.

How It Works

When darkMode is set to 'media', Tailwind leverages the @media (prefers-color-scheme: dark) CSS media query to activate dark mode styles. You still use the dark: prefix in your classes, but instead of relying on a dark class, Tailwind applies these styles whenever the user’s system signals a dark mode preference. No JavaScript is needed—everything happens at the CSS level.

Configuration

Enable media-based dark mode in your tailwind.config.js:

module.exports = {
  darkMode: 'media', // Enables media query-based dark mode
  content: ['./src/**/*.{html,js,ts,jsx,tsx}'], // Adjust paths to your files
  theme: {
    extend: {},
  },
  plugins: [],
};

Example Implementation

Here’s how it looks in action with no JavaScript required:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Media-Based Dark Mode</title>
  <link href="/path/to/tailwind.css" rel="stylesheet">
</head>
<body class="bg-white dark:bg-gray-900 text-gray-900 dark:text-white p-6">
  <h1 class="text-2xl">Hello, Dark Mode!</h1>
  <p class="mt-2">
    This page adapts automatically to your system's color scheme.
  </p>
</body>
</html>
  • No Toggle Needed: The theme switches instantly when the user changes their OS settings.
  • Simplicity: Works out of the box with Tailwind’s dark: utilities.

Use Cases

  • Minimalist Projects: Great for simple websites or landing pages where manual toggling isn’t a priority.
  • System-Aligned Apps: Perfect for native-like experiences in progressive web apps (PWAs) or tools that integrate with OS behavior.
  • Low Maintenance: Suits developers who want a “set it and forget it” solution.

Advantages

  • Zero JavaScript overhead—purely CSS-driven.
  • Respects user preferences without additional UI elements.
  • Seamless integration with modern OS ecosystems.

Considerations

  • No manual override unless you add custom logic.
  • Users without system-level dark mode (e.g., older devices) won’t see the effect.
  • Less flexibility for custom theme switching.

Choosing the Right Strategy

Both approaches leverage Tailwind’s powerful dark: prefix, but your choice depends on your project’s goals:

  • Opt for class if you want an interactive, user-driven experience with a toggle button or settings panel.
  • Choose media for a passive, automatic solution that aligns with system settings and requires no extra code.

For greater flexibility and to showcase a practical, hands-on example, this guide will proceed with the class-based approach. This allows us to explore toggle functionality, user preference persistence, and dynamic styling—key elements for many real-world applications. However, if you prefer the simplicity of media queries, the concepts here (e.g., styling with dark:) still apply—just skip the JavaScript and let the browser handle the rest!

Implementing Dark Mode

Step 1: Add a Dark Mode Toggle Button

To allow users to switch between light and dark modes, add a toggle button in your HTML file:

<button id="theme-toggle" class="p-2 bg-gray-200 dark:bg-gray-800 text-black dark:text-white rounded">
  Toggle Dark Mode
</button>

Step 2: JavaScript for Theme Toggle

Next, write JavaScript to handle the theme switch and save the user’s preference in localStorage.

const toggle = document.getElementById('theme-toggle');
const root = document.documentElement;

// Check for saved user preference and apply it
if (localStorage.getItem('theme') === 'dark') {
  root.classList.add('dark');
}

toggle.addEventListener('click', () => {
  if (root.classList.contains('dark')) {
    root.classList.remove('dark');
    localStorage.setItem('theme', 'light');
  } else {
    root.classList.add('dark');
    localStorage.setItem('theme', 'dark');
  }
});

This script:
✔ Checks the user’s stored theme preference on page load.
✔ Applies dark mode if the saved theme is dark.
✔ Toggles dark mode when the button is clicked.
✔ Stores the preference in localStorage so it persists after page refresh.

Styling with Dark Mode in Tailwind CSS

Example 1: Background and Text Colors

Tailwind provides the dark: prefix to define styles for dark mode:

<div class="bg-white text-black dark:bg-gray-900 dark:text-white p-4">
  <h1 class="text-xl">Welcome to Dark Mode</h1>
  <p>This is a dark mode example using Tailwind CSS.</p>
</div>

Example 2: Tailwind Utilities in Dark Mode

Dark mode works seamlessly with all Tailwind utilities, including borders, hover states, and buttons.

Border Colors

<div class="border border-gray-300 dark:border-gray-600 p-4">
  This box has a different border color in dark mode.
</div>

Hover States

<button class="p-2 bg-gray-300 hover:bg-gray-400 dark:bg-gray-700 dark:hover:bg-gray-600">
  Hover Me
</button>

Customizing Dark Mode in Tailwind

You can define custom colors in your Tailwind configuration file:

module.exports = {
  theme: {
    extend: {
      colors: {
        dark: {
          bg: '#1e293b', // Custom dark background
          text: '#f1f5f9', // Custom text color
          accent: '#64748b', // Custom accent color
        },
      },
    },
  },
};

Now, you can use these custom colors in your HTML:

<div class="bg-dark-bg text-dark-text dark:bg-dark-accent p-4">
  Custom Dark Mode
</div>

This allows for a unique and branded dark mode experience beyond the default Tailwind colors.

Testing and Debugging Dark Mode

To make sure your dark mode works perfectly for all users, it’s important to test and fix any issues that might pop up. Here are some practical tips to help you check that everything runs smoothly:

1. Use Browser Developer Tools

Most modern browsers, like Chrome and Edge, have built-in tools to help you test dark mode without changing your actual system settings. Open the Developer Tools by pressing F12 or Ctrl + Shift + I (Cmd + Option + I on a Mac). Look for the "Rendering" tab (you might need to click the three-dot menu to find it), then scroll down to the "Emulate CSS media features" section. Here, you can switch "prefers-color-scheme" to "dark" or "light" to see how your site looks in each mode instantly. This is super handy for testing your darkMode: 'media' setup or checking how your dark: classes behave.

2. Test with System Preferences

Another way to test is by turning on dark mode in your computer’s operating system—like Windows, macOS, or Linux—and seeing if your website adjusts automatically. Go to your OS settings (e.g., "Display" or "Appearance"), enable dark mode, and refresh your site. This checks if the darkMode: 'media' option in Tailwind is working as expected, picking up your system’s preference without needing a manual toggle. It’s a real-world test to ensure users with dark mode enabled see the right design.

3. Cross-Browser Testing

Since people use different web browsers, you’ll want to make sure dark mode looks good everywhere. Open your site in popular browsers like Chrome, Firefox, Microsoft Edge, and Safari (especially if you’re on a Mac). Check that colors, hover effects, and transitions work the same across all of them. Some browsers might handle dark mode media queries or Tailwind classes a bit differently, so this step helps you catch and fix any odd inconsistencies.

Final Thoughts

Implementing dark mode in Tailwind CSS is incredibly simple and powerful. With just a few steps, you can:
✔ Enable dark mode support using Tailwind’s dark: utility.
✔ Allow users to switch themes with a JavaScript toggle.
✔ Customize dark mode with custom colors and styles.
✔ Ensure a seamless experience using localStorage and system settings.

Adding dark mode enhances usability, accessibility, and aesthetics for your website or app. Start implementing it today and take your design to the next level! 🚀

For more details, check out the official: Tailwind CSS Dark Mode Documentation.

Topics Covered

About Author

I'm Maulik Paghdal, the founder of Script Binary and a passionate full-stack web developer. I have a strong foundation in both frontend and backend development, specializing in building dynamic, responsive web applications using Laravel, Vue.js, and React.js. With expertise in Tailwind CSS and Bootstrap, I focus on creating clean, efficient, and scalable solutions that enhance user experiences and optimize performance.