Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 18 additions & 1 deletion src/components/theme-provider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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 `<head>` 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 <ScriptOnce>{getThemeScript(storageKey, defaultTheme)}</ScriptOnce>;
}

function applyResolvedTheme(resolved: ResolvedTheme) {
const root = document.documentElement;
root.classList.remove("light", "dark");
Expand Down Expand Up @@ -90,7 +108,6 @@ export function ThemeProvider({

return (
<ThemeProviderContext value={{ resolvedTheme, theme, setTheme }}>
<ScriptOnce>{getThemeScript(themeStorageKey, defaultTheme)}</ScriptOnce>
{children}
</ThemeProviderContext>
);
Expand Down
5 changes: 3 additions & 2 deletions src/routes/__root.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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";
Expand Down Expand Up @@ -79,9 +79,10 @@ function RootDocument({ children }: { children: React.ReactNode }) {
return (
<html lang="en" suppressHydrationWarning>
<head>
<ThemeScript defaultTheme="system" storageKey="theme" />
<HeadContent />
</head>
<body>
<body suppressHydrationWarning>
<ThemeProvider defaultTheme="system" storageKey="theme">
<AuthSessionRefresher />
<PostHogProvider>
Expand Down
Loading