Skip to main content

Command Palette

Search for a command to run...

How to Set Up Dark Mode with TailwindCSS 4

A quick guide to understand how to handle Dark Mode in Tailwindcss 4

Updated
4 min read
How to Set Up Dark Mode with TailwindCSS 4
G

CTO of Allocations.com, a finance SaaS Miami-based, I am running a YouTube channel: @codewithguillaume. With 15 years of exp. as a freelancer, consultant, and Lead Developer, I have led dozens of engineering teams across Paris, London, and Berlin. I am father of 2 and I live in Dubai.

TailwindCSS 4 introduced a major shift in how themes, tokens, and variants work.
And one of the biggest changes: dark mode no longer works out of the box.

If you upgraded from Tailwind 3 to 4, you probably noticed this instantly:

  • dark:bg-black does nothing

  • adding .dark on <html> has no effect

  • dark: classes simply don’t get generated

Why?
Because TailwindCSS v4 removed the old darkMode: 'class' configuration and the internal dark variant.

But the good news is:
➡️ Dark mode is still fully supported
➡️ You just need to enable it explicitly
➡️ The new setup is actually more powerful

In this guide, I’ll show you exactly how to set up dark mode in TailwindCSS 4, step-by-step.


1. The Key Change in TailwindCSS 4

In TailwindCSS v3 and below, dark mode was enabled via:

module.exports = {
  darkMode: "class",
};

In TailwindCSS v4, the entire config file is gone, and so is that option.

Variants (like dark:) now must be declared manually using the new @custom-variant rule.

This is the heart of the solution.


2. Create Your Dark Variant

In your global CSS file (usually src/styles/global.css or app.css):

@import "tailwindcss";

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

This line simply tells Tailwind:

Generate dark: classes that apply whenever an element is inside .dark.

This is equivalent to Tailwind v3’s .dark strategy.


3. Enable Native Browser Color Scheme

Still in your CSS:

:root {
  color-scheme: light;
}

.dark {
  color-scheme: dark;
}

This ensures built-in elements (inputs, scrollbars, form elements) also switch to dark mode.


4. Add Dark Styles

Now you can write Tailwind like before:

@layer base {
  html {
    @apply bg-white text-black dark:bg-neutral-950 dark:text-neutral-100;
  }

  p {
    @apply text-neutral-600 dark:text-neutral-400;
  }
}

Yes — dark: works exactly as in Tailwind 3.


5. Add Your Theme Tokens (Optional)

TailwindCSS 4 introduces a powerful @theme rule:

@theme {
  --color-primary-500: #00e983;
  --color-primary-700: #00c269;
  --font-sans: "Geist", sans-serif;
}

Your theme tokens are now auto-generated as utilities:

  • text-primary-500

  • bg-primary-500

  • font-sans


6. Toggle Dark Mode with JavaScript

Tailwind 4 does not change how you toggle dark mode.
Just add/remove .dark on <html>:

document.documentElement.classList.toggle("dark");

Or save it in localStorage:

const toggle = () => {
  const html = document.documentElement;
  const dark = html.classList.toggle("dark");
  localStorage.setItem("dark-mode", dark);
};

if (localStorage.getItem("dark-mode") === "true") {
  document.documentElement.classList.add("dark");
}

7. Example: Complete Working Setup

Here is a minimal working example:

global.css

@import "tailwindcss";

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

:root {
  color-scheme: light;
}
.dark {
  color-scheme: dark;
}

@layer base {
  html {
    @apply bg-white text-black dark:bg-neutral-950 dark:text-neutral-100;
  }
}

HTML / Astro / React

<button onclick="document.documentElement.classList.toggle('dark')">
  Toggle
</button>

<div class="p-4 bg-white dark:bg-red-500">
  Dark mode test
</div>

When you click the button, the card turns red in dark mode.


8. Common Pitfalls (and Fixes)

❌ 1. Forgetting to add @custom-variant

Dark mode will never work without:

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

❌ 2. Putting @theme inside @layer

It must be at top level.

❌ 3. Your framework overwrites <html class="dark">

Astro layouts often do this accidentally.

❌ 4. Missing CSS import

Make sure your global CSS is loaded.


9. Why Tailwind 4 Changed This

TailwindCSS 4 is designed around:

  • Native CSS

  • Zero JS config

  • Custom tokens

  • Full CSS power with Tailwind utilities

  • Fine-grained variant control

  • Smaller CSS output

By moving variants to CSS, Tailwind becomes:

  • More flexible

  • Easier to customize

  • Better for future tooling

  • Less magic, more explicit control


Conclusion

TailwindCSS 4’s dark mode setup is different, but once you understand it, it’s actually cleaner and more powerful than before.

To summarize:

✅ 1. Import Tailwind

✅ 2. Declare the dark variant

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

✅ 3. Add color-scheme

✅ 4. Add dark:* classes

✅ 5. Toggle .dark with JavaScript

Once you do these steps, dark mode works exactly as expected.