Skip to content

Commit e7b1ce3

Browse files
committed
fix: theme persistence — read localStorage directly instead of relying on html class
React hydration can reset the html className set by the inline script. ThemeProvider now reads directly from localStorage (then cookie fallback) and re-applies the class, ensuring light mode survives page refresh. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 2eebec6 commit e7b1ce3

1 file changed

Lines changed: 20 additions & 2 deletions

File tree

‎app/src/components/ThemeProvider.tsx‎

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,27 @@ export function ThemeProvider({ children }: { children: React.ReactNode }) {
1717
const [mounted, setMounted] = useState(false);
1818

1919
useEffect(() => {
20-
// Read the class that the inline script already applied (avoids flash).
20+
// Read persisted preference directly (most reliable — survives hydration resets).
21+
let initialTheme: Theme = 'dark';
22+
try {
23+
const stored = localStorage.getItem('wl-theme');
24+
if (stored === 'light' || stored === 'dark') {
25+
initialTheme = stored;
26+
} else {
27+
// Fallback: cookie (cross-subdomain)
28+
const m = document.cookie.match(/wl-theme=(dark|light)/);
29+
if (m) initialTheme = m[1] as Theme;
30+
}
31+
} catch {
32+
// Fallback: read whatever class the inline script set
33+
initialTheme = document.documentElement.classList.contains('light') ? 'light' : 'dark';
34+
}
35+
36+
// Re-apply class in case hydration cleared it
2137
const root = document.documentElement;
22-
const initialTheme: Theme = root.classList.contains('light') ? 'light' : 'dark';
38+
root.classList.remove('dark', 'light');
39+
root.classList.add(initialTheme);
40+
2341
setThemeState(initialTheme);
2442
setMounted(true);
2543
}, []);

0 commit comments

Comments
 (0)