EngineeringJune 20, 20265 min read
Zero-Flicker Dark Mode in Next.js Server Components
Prevent layout shifts and flash-of-light-mode hydration errors using pre-hydration scripting.
AD
Abhinav Dash
Founder & Software Engineer
The Hydration Flash Problem
When using Next.js, pages are pre-rendered on the server. If your server renders the page in light mode, but the client prefers dark mode, the user will experience a momentary flash of bright white background before the theme synchronizes.
The Script Tag Fix
To solve this, inject a small, blocking JavaScript script into the <head> of the document before React starts hydrating the HTML.
<head>
<script
dangerouslySetInnerHTML={{
__html: `
try {
if (localStorage.theme === 'dark' || (!('theme' in localStorage) && window.matchMedia('(prefers-color-scheme: dark)').matches)) {
document.documentElement.classList.add('dark');
} else {
document.documentElement.classList.remove('dark');
}
} catch (_) {}
`,
}}
/>
</head>How it works
- The script runs synchronously immediately when it is parsed.
- It toggles the class `dark` on the root element.
- Because it executes before CSS layout rendering, the browser paints the dark theme background right away.
- No flashing, no layout shifts, and no hydration errors.