Tailwind CSS - Dark Mode

Dark mode is a feature in many operating systems that changes the screen's color scheme to darker shades. It improves visibility in low-light conditions and offers a gentler viewing experience compared to traditional bright themes.

Tailwind CSS simplifies the process of implementing dark mode on your website. It provides a built-in dark mode variant that allows you to easily style your site for both light and dark themes.

You can define specific styles for dark mode using Tailwind's dark variant, which ensures that your website looks great in both light and dark settings.

Example

<!DOCTYPE html>
<html lang="en" class="dark">
<head>
  <script src="https://cdn.tailwindcss.com"></script>
</head> 

<body class="bg-gray-200 p-4">
    <div class="grid grid-cols-2 gap-6">
        <!-- Light Mode Card -->
        <div class="bg-white p-6 rounded-lg shadow-xl">
            <h2 class="text-xl font-semibold mb-2 text-gray-800">
                Light Mode
            </h2>
            <p class="text-gray-600">
                This is the light mode version of the card. 
                The background is white, and the text is in 
                shades of gray, offering a clean and bright 
                appearance.
            </p>
        </div>
        <!-- Dark Mode Card -->
        <div class="bg-gray-900 p-6 rounded-lg shadow-xl">
            <h2 class="text-xl font-semibold mb-2 text-gray-100">
                Dark Mode
            </h2>
            <p class="text-gray-400">
                This is the dark mode version of the card. 
                The background is dark gray, and the text 
                is in lighter shades, making it easier to 
                read in low-light conditions.
            </p>
        </div>
    </div>
</body>

</html>

This example shows how a card component looks in both light mode and dark mode, displayed side by side. The light mode card has a white background with dark text, while the dark mode card has a dark background with lighter text for easy readability.

Manually Toggling Dark Mode with Tailwind CSS

To manually control dark mode in your Tailwind CSS project, you can use the "selector" strategy rather than relying on the system's default setting for handling dark mode. Here's how to configure it.

In your tailwind.config.js file, set up dark mode as follows:

module.exports = {
  darkMode: 'selector',
  // ...
}

With this setup, dark mode styles will apply when a specific class (e.g., dark) is present on an element, rather than depending on the user's system settings.

Example: Without Dark Mode

<html>
<body>
    <!-- This will be white -->
    <div class="bg-white dark:bg-black">
        <!-- ... -->
    </div>
</body>

</html>

Example: With Dark Mode Enabled

<html class="dark">
<body>
    <!-- This will be black -->
    <div class="bg-white dark:bg-black">
        <!-- ... -->
    </div>
</body>
</html>

If you use a prefix in your Tailwind configuration, make sure to apply it to the dark mode class. For instance, with a prefix like tw-, you should use tw-dark to activate dark mode. Also, to manage when the dark class is applied, you can use JavaScript to check user preferences (such as from localStorage) and update the HTML accordingly.

Customizing Dark Mode Selector

In some frameworks, dark mode is handled differently, using unique class names or methods. Tailwind CSS allows you to customize how dark mode is applied by defining a custom selector in your configuration.

You can set up a custom selector by configuring darkMode with an array, like this:

/** @type {import('tailwindcss').Config} */
module.exports = {
  darkMode: ['selector', '[data-mode="dark"]'],
  // ...
}

Tailwind will wrap your custom selector with the :where() pseudo-class to ensure that its specificity matches that of the default media-based strategy.

.dark\:underline:where([data-mode="dark"], [data-mode="dark"] *) {
  text-decoration-line: underline;
}

Supporting Both System Preferences and Manual Selection

You can use the selector strategy to support both system preferences and manual theme toggling. This example shows how to manage themes using localStorage and the window.matchMedia() API.

// Check and apply the theme on page load
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');
}

// To set light mode
localStorage.theme = 'light';

// To set dark mode
localStorage.theme = 'dark';

// To respect the OS preference
localStorage.removeItem('theme');

You have complete flexibility in how you implement this, whether you choose to manage preferences on the client side or store them on the server and apply them during page rendering.

Customizing the Dark Mode Variant

If you prefer to use your own dark mode variant rather than Tailwind's default one, you can customize it in your tailwind.config.js file. To set up a custom dark mode variant, use the following configuration.

/** @type {import('tailwindcss').Config} */
module.exports = {
  darkMode: ['variant', '&:not(.light *)'],
  // ...
}

With this method, Tailwind will not alter the selector you provide. Therefore, be careful with its specificity and consider using the :where() pseudo-class to match the specificity of other Tailwind utilities.

Using Multiple Selectors

If you need to accommodate different scenarios for enabling dark mode, you can specify multiple selectors in an array within your configuration file.

/** @type {import('tailwindcss').Config} */
module.exports = {
    darkMode: ['variant', [
    '@media (prefers-color-scheme: dark) { &:not(.light *) }',
    '&:is(.dark *)',
    ]],
    // ...
}

This configuration allows you to handle various dark mode use cases by specifying multiple selectors.