diff --git a/packages/providers/src/theme.tsx b/packages/providers/src/theme.tsx index b8afe83d..81d2dd2e 100644 --- a/packages/providers/src/theme.tsx +++ b/packages/providers/src/theme.tsx @@ -58,34 +58,29 @@ ThemeContext.displayName = 'ThemeContext'; const PREFERS_LIGHT_MQ = '(prefers-color-scheme: light)'; -/** - * Return the theme preference indicated by the system - */ -function getPreferredTheme() { - return window.matchMedia(PREFERS_LIGHT_MQ).matches ? Theme.light : Theme.dark; -} - const THEME_KEY = 'myst:theme'; -const CLIENT_THEME_SOURCE = ` - const savedTheme = localStorage.getItem(${JSON.stringify(THEME_KEY)}); +/** + * A blocking element that runs on the client before hydration to update the preferred class + * This ensures that the hydrated state matches the non-hydrated state (by updating the DOM on the + * client between SSR on the server and hydration on the client) + */ +export function BlockingThemeLoader({ useLocalStorage }: { useLocalStorage: boolean }) { + const LOCAL_STORAGE_SOURCE = `localStorage.getItem(${JSON.stringify(THEME_KEY)})`; + const CLIENT_THEME_SOURCE = ` + const savedTheme = ${useLocalStorage ? LOCAL_STORAGE_SOURCE : 'null'}; const theme = window.matchMedia(${JSON.stringify(PREFERS_LIGHT_MQ)}).matches ? 'light' : 'dark'; const classes = document.documentElement.classList; const hasAnyTheme = classes.contains('light') || classes.contains('dark'); if (!hasAnyTheme) classes.add(savedTheme ?? theme); `; -/** - * A blocking element that runs before hydration to update the preferred class - */ -export function BlockingThemeLoader() { return