Web development

The three dark mode strategies

Tailwind dark mode has three strategies: the system media query, a class on html, or a data-theme attribute. Each one decides who owns the theme.

Key points

  • By default dark: follows prefers-color-scheme, with no JavaScript.
  • A class on html is enough for a two-state toggle.
  • data-theme is the right choice when the theme comes from the server.

Tailwind CSS offers three dark mode strategies: the system media query, a class on html, a data-theme attribute. They differ in who owns the theme and how much JavaScript you need.

1. System: no JavaScript

This is what dark: does by default: it emits an @media (prefers-color-scheme: dark). The site follows the operating system and remembers no choice.


  Testo leggibile in entrambi i temi.

2. A class on the document

For a two-state toggle you override the variant with @custom-variant:

@import "tailwindcss";

@custom-variant dark (&:where(.dark, .dark *));

Then add or remove dark on html. The variant uses :where(), so specificity stays at zero and normal utilities still win.

3. A data-theme attribute

@import "tailwindcss";

@custom-variant dark (&:where([data-theme="dark"], [data-theme="dark"] *));

With data-theme you can add a third state, system, and read the value on the server. The markup carries the decision: <html data-theme="dark">.

Which one to pick

StrategyWho decidesNeeds JavaScriptWhen to use it
Media queryOperating systemNoA site with no toggle
ClassToggle in the browserYesTwo states with a saved preference
data-themeServer or browserYes, to change itPer-user theme or server-rendered theme

The limitation

The saved theme is read after the first paint: the browser shows light for a frame and then dark. The script has to sit inline in the head, before anything else. If the preference lives in a database, the server must render class or data-theme in the first response, otherwise the flash remains.

Where to continue

The catalogue holds theme toggles, Tailwind components and the dashboard-analytics block from bag/ui, with a dark sidebar. The flash is explained in dark mode without a flash, the second design system in dark mode without a second design system; the comparison of CSS approaches is in Tailwind vs CSS Modules.

Frequently asked questions

What is the default dark mode strategy in Tailwind?

The prefers-color-scheme media query. The dark variant follows the operating system until you override it with @custom-variant.

Is a class better than a data-theme attribute?

A class is shorter and enough for two states. data-theme pays off when the theme comes from the server or when you need a third state, system, next to light and dark.

How do you avoid the flash of the wrong theme?

With an inline script in the head that sets the class or attribute before the first paint. If the theme lives in a database, the server must render it in the first response.

Does dark mode hurt accessibility?

It can, if contrast is checked only in the light theme. A dark grey on black stays unreadable even when the theme itself works.

Does a dark theme need a second design system?

No, the same tokens with different values are enough. A second set of components doubles maintenance and creates divergences that are hard to close.