From 89c20e06a070e719cf47816300683c2eb33c5c5f Mon Sep 17 00:00:00 2001
From: omoh5
Date: Thu, 30 Jul 2026 07:25:53 +0000
Subject: [PATCH] fix(frontend): guard against SSR/hydration mismatch in theme
provider (#1083)
Add blocking inline script in that reads localStorage theme preference before first paint, preventing flash-of-wrong-theme when client theme differs from server-rendered default. Add comprehensive JSDoc comments documenting the SSR/hydration strategy in both theme-provider.tsx and layout.tsx.
---
frontend/src/app/layout.tsx | 45 +++++++++++++++++++++--
frontend/src/context/theme-provider.tsx | 47 +++++++++++++++++++++++++
2 files changed, 90 insertions(+), 2 deletions(-)
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.
+ */}
+
+
` element
+ * and sees that the client DOM has a `dark` class the server did not
+ * produce, it logs a console warning.
+ *
+ * We solve both problems with a two-part approach inside `layout.tsx`:
+ *
+ * - **Blocking inline `