Hybrid storage
Use cookies for SSR and localStorage for cross-tab sync.
storage="hybrid" stores the theme in a cookie and mirrors it to localStorage. The pre-paint bootstrap reads the cookie before the first paint. The Next ThemeProvider does not call cookies(). localStorage keeps other tabs in sync.
Try it
Switch the theme and watch both stores update: the cookie is what the bootstrap reads before paint, localStorage carries the change to other tabs. This demo uses its own key, so it never touches the page theme.
cookie …localStorage …
Hedy Lamarr
Cookie first, mirrored to localStorage
Open this page in a second tab and switch here: the other tab follows.
<ThemeProvider storage="hybrid" storageKey="theme">
{children}
</ThemeProvider>Root layout
import { ThemeProvider } from "@wrksz/themes/next";
export default function RootLayout({ children }: { children: React.ReactNode }) {
return (
<html lang="en" suppressHydrationWarning>
<body>
<ThemeProvider
storage="hybrid"
defaultTheme="system"
enableSystem
disableTransitionOnChange
>
{children}
</ThemeProvider>
</body>
</html>
);
}Use @wrksz/themes/next in App Router layouts so the anti-flash script is injected through useServerInsertedHTML.
Theme toggle
"use client";
import { useTheme } from "@wrksz/themes/client";
export function ThemeToggle() {
const { theme, resolvedTheme, setTheme } = useTheme();
return (
<div>
<p>
Selected: {theme}
<br />
Resolved: {resolvedTheme}
</p>
<button type="button" onClick={() => setTheme("light")}>
Light
</button>
<button type="button" onClick={() => setTheme("dark")}>
Dark
</button>
<button type="button" onClick={() => setTheme("system")}>
System
</button>
</div>
);
}Open the same app in two tabs, switch the theme in one tab, and the other tab updates through the storage event.
CSS
:root {
--bg: #ffffff;
--fg: #0a0a0a;
}
:root.dark {
--bg: #0a0a0a;
--fg: #fafafa;
}
body {
background: var(--bg);
color: var(--fg);
}Avoid mixing this with a broad @media (prefers-color-scheme: dark) fallback for the same tokens. The provider sets the correct class before hydration.