From f1fd4836b54979fd63005db51415453713442547 Mon Sep 17 00:00:00 2001 From: "posthog[bot]" <206114724+posthog[bot]@users.noreply.github.com> Date: Sun, 12 Jul 2026 17:30:55 +0000 Subject: [PATCH] fix(hydration): harden root document hydration path Move the theme resolution script to `` so it runs during HTML parsing, ahead of body hydration, and add `suppressHydrationWarning` to `` to cover extension-injected attribute diffs on the root document. Reduces the recurring React #418 mismatch on whole-document hydration. Generated-By: PostHog Code Task-Id: c0b36c28-ba43-47a4-aa47-00661c9afcd3 --- src/components/theme-provider.tsx | 19 ++++++++++++++++++- src/routes/__root.tsx | 5 +++-- 2 files changed, 21 insertions(+), 3 deletions(-) diff --git a/src/components/theme-provider.tsx b/src/components/theme-provider.tsx index 76c7315f8..37b7465f5 100644 --- a/src/components/theme-provider.tsx +++ b/src/components/theme-provider.tsx @@ -35,6 +35,24 @@ function getThemeScript(storageKey: string, defaultTheme: Theme) { return `(function(){try{var t=localStorage.getItem(${key});if(t!=='light'&&t!=='dark'&&t!=='system'){t=${fallback}}var d=matchMedia('(prefers-color-scheme: dark)').matches;var r=t==='system'?(d?'dark':'light'):t;var e=document.documentElement;e.classList.add(r);e.style.colorScheme=r}catch(e){}})();`; } +type ThemeScriptProps = { + defaultTheme?: Theme; + storageKey?: string; +}; + +/** + * Inline script that resolves and applies the theme to `document.documentElement` + * before paint. It must render in `` so it runs during HTML parsing, ahead + * of body hydration — otherwise its mutation of the root element races React's + * whole-document hydration and can surface as a #418 mismatch. + */ +export function ThemeScript({ + defaultTheme = "system", + storageKey = defaultThemeStorageKey, +}: ThemeScriptProps) { + return {getThemeScript(storageKey, defaultTheme)}; +} + function applyResolvedTheme(resolved: ResolvedTheme) { const root = document.documentElement; root.classList.remove("light", "dark"); @@ -90,7 +108,6 @@ export function ThemeProvider({ return ( - {getThemeScript(themeStorageKey, defaultTheme)} {children} ); diff --git a/src/routes/__root.tsx b/src/routes/__root.tsx index 64ea0204b..23b4e9cb0 100644 --- a/src/routes/__root.tsx +++ b/src/routes/__root.tsx @@ -10,7 +10,7 @@ import type { AuthSession } from "#/lib/auth.functions"; import { AppHotkeysProvider } from "#/lib/hotkeys"; import { seo } from "#/lib/seo"; import { getAuthSessionQueryOptions } from "#/lib/session-query"; -import { ThemeProvider } from "../components/theme-provider"; +import { ThemeProvider, ThemeScript } from "../components/theme-provider"; import PostHogProvider from "../integrations/posthog/provider"; import TanStackQueryDevtools from "../integrations/tanstack-query/devtools"; import appCss from "../styles.css?url"; @@ -79,9 +79,10 @@ function RootDocument({ children }: { children: React.ReactNode }) { return ( + - +