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)