DEV Community

Cover image for Next.js Dark Mode Without the Flash (Tailwind v4)
Dev Encyclopedia
Dev Encyclopedia

Posted on • Originally published at devencyclopedia.com

Next.js Dark Mode Without the Flash (Tailwind v4)

Every dark mode implementation has the same enemy: the flash.

The page renders in light mode, then instantly switches to dark. It happens because JavaScript applies the CSS class after the HTML is already painted -- and by then it's too late.

Why It Happens

Browsers paint HTML before JavaScript runs. By the time your JS reads localStorage and adds dark to <html>, the first frame is already done.

The only real fix is a blocking inline script in <head> that runs before any rendering. That's what next-themes handles automatically.

The Key Pieces

1. suppressHydrationWarning goes on <html>, not <body>

Most guides get this wrong. Without it on the right element, you'll still see hydration warnings.

2. Tailwind v4 dropped darkMode: 'class'

Add this to globals.css instead:

@custom-variant dark (&:where(.dark, .dark *));
Enter fullscreen mode Exit fullscreen mode

This is the #1 reason dark mode breaks after upgrading to Tailwind v4.

3. Mount-guard your toggle button

useTheme() returns undefined during hydration. Render null until mounted or your toggle will flicker.


Full setup with complete code, Cloudflare Pages notes, and troubleshooting:
👉 https://devencyclopedia.com/blog/nextjs-dark-mode-without-flash

Top comments (0)