Building Dark Mode in Next.js Without the Flash
Dark mode seems simple. Then you see the flash.
When a user loads your page, the server sends the default theme. The user sees a white screen for a split second before the dark theme kicks in. This is a bad user experience.
The problem exists because the server cannot read localStorage. The server only knows the theme after the browser runs your JavaScript.
Here is how to fix it.
The Solution: The Inline Script
You must apply the theme before React starts. Put a small script in your
tag. This script reads the preference and adds the dark class immediately.Use these steps:
- Add a script in your RootLayout to check localStorage.
- Use suppressHydrationWarning on your tag. This stops React from complaining about the theme mismatch.
- Use a ThemeProvider to manage state and sync with localStorage.
- Use CSS variables with Tailwind for smooth color transitions.
Why this works: The script runs before the page renders. It prevents the visual jump.
Handling Images
Images often need different versions for light and dark modes. You have two choices:
- CSS Method: Use display none and display block to swap images based on the .dark class. This is the fastest way.
- Client Method: Use a component that checks the theme and picks the right image source.
Pro Tip for Server-Side Content
If you need the server to know the theme for charts or heavy content, use cookies instead of localStorage.
- Store the theme in a cookie.
- Use Next.js middleware to read that cookie.
- Pass the theme to your layout via headers.
This allows the server to send the correct HTML from the start.
Summary for a flash-free system: • Use an inline script in the
• Use suppressHydrationWarning • Manage state with a Context Provider • Listen for system preference changesThis approach works for production apps. It ensures instant switching and zero flashes.