Part 44: Building a Dark Mode Toggle with LocalStorage & Zero Flicker
When implementing manual dark mode, a common issue is the "White Flash of Death"—the page briefly renders in white before JavaScript reads localStorage and applies the dark class.
1. The Anti-Flicker Inline Script
Place this tiny script directly in your <head> tag in index.html before any CSS or body content renders:
<script>
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');
}
</script>
2. The Interactive Toggle Button
import { useState, useEffect } from 'react';
export default function DarkModeToggle() {
const [isDark, setIsDark] = useState(false);
useEffect(() => {
setIsDark(document.documentElement.classList.contains('dark'));
}, []);
const toggleTheme = () => {
if (isDark) {
document.documentElement.classList.remove('dark');
localStorage.theme = 'light';
setIsDark(false);
} else {
document.documentElement.classList.add('dark');
localStorage.theme = 'dark';
setIsDark(true);
}
};
return (
<button
onClick={toggleTheme}
className="p-2.5 rounded-xl bg-slate-100 dark:bg-slate-800 text-slate-800 dark:text-slate-100 transition"
aria-label="Toggle theme"
>
{isDark ? '☀️ Light Mode' : '🌙 Dark Mode'}
</button>
);
}
Key Takeaways
- Prevent theme flickering by executing an inline theme detection script in
<head>. - Persist preferences to
localStorage.theme.
In Part 45, we enter Module 8 to master Transitions, Transforms & Animations!

