Dark Mode

Using Elements CSS to style your site in dark mode.


# Usage

Now that dark mode is a first-class feature of many operating systems, it’s becoming more and more common to design a dark version of your website to go along with the default design.

To make this as easy as possible, Elements includes a dark variant that lets you style your site differently when dark mode is enabled:

<html class="dark">
<body>
<div class="bg-white dark:bg-gray-800">
<h1 class="text-gray-900 dark:text-white">Dark mode is here!</h1>
<p class="text-gray-600 dark:text-gray-300">
Lorem ipsum...
</p>
</div>
</body>
</html>

Now whenever the dark class is added, dark:{class} classes will take precedence over unprefixed classes.

To keep file size down, dark variants are only generated for color-related classes, which includes text color, background color, border color, gradients, and placeholder color.


# Toggling dark mode

Elements uses dark mode toggling instead of relying on the operating system preference, prefering to use a class strategy instead of a media strategy.

Instead of dark:{class} classes being applied based on prefers-color-scheme, they will be applied whenever dark class is present earlier in the HTML tree.

<html>
<body>
<!-- Will be white -->
<div class="bg-white dark:bg-black">
<!-- ... -->
</div>
</body>
</html>
<!-- Dark mode enabled -->
<html class="dark">
<body>
<!-- Will be black -->
<div class="bg-white dark:bg-black">
<!-- ... -->
</div>
</body>
</html>

How you add the dark class to the html element is up to you, but a common approach is to use a bit of JS that reads a preference from somewhere (like localStorage) and updates the DOM accordingly.

Here’s a simple example of how you can support light mode, dark mode, as well as respecting the operating system preference:

// On page load or when changing themes, best to add inline in `head` to avoid FOUC
if (localStorage.theme === 'dark' || (!('theme' in localStorage) && window.matchMedia('(prefers-color-scheme: dark)').matches)) {
document.querySelector('html').classList.add('dark')
} else {
document.querySelector('html').classList.remove('dark')
}

// Whenever the user explicitly chooses light mode
localStorage.theme = 'light'

// Whenever the user explicitly chooses dark mode
localStorage.theme = 'dark'

// Whenever the user explicitly chooses to respect the OS preference
localStorage.removeItem('theme')

Again you can manage this however you like, even storing the preference server-side in a database and rendering the class on the server — it’s totally up to you.


# Stacking with other variants

The dark variant can be combined with both responsive variants and state variants (like hover and focus):

<button class="lg:dark:hover:bg-white ...">
<!-- ... -->
</button>

The responsive variant needs to come first, then dark, then the state variant for this to work.