diff --git a/frontend/src/app/layout.tsx b/frontend/src/app/layout.tsx index e039ba12..f063814f 100644 --- a/frontend/src/app/layout.tsx +++ b/frontend/src/app/layout.tsx @@ -59,9 +59,50 @@ export default function RootLayout({ }: Readonly<{ children: React.ReactNode; }>) { + // suppressHydrationWarning allows the blocking inline script in to + // mutate the `dark` class on without React logging a hydration + // mismatch warning. See theme-provider.tsx for the full strategy. return ( - {/* TODO: revisit if i18n is introduced */} - + + + {/* + Blocking inline script that reads the user's stored theme preference + from localStorage and applies the `dark` class to BEFORE the + browser paints a single pixel. This prevents the flash-of-wrong-theme + (FART) when the server renders a default theme class that differs from + the user's persisted preference. + + The `suppressHydrationWarning` prop on is the companion measure: + after this script mutates the class, React will see a mismatch between + server-rendered (no `dark` class) and the client DOM (possibly + `dark` class) and would normally emit a console warning. + suppressHydrationWarning tells React to skip that check for this + element because the discrepancy is intentional and resolved before + hydration completes. + + Flow: inline script runs → class set → browser paints → React hydrates + (suppressHydrationWarning) → next-themes ThemeProvider takes over. + */} +