Server-provided theme
Eliminate SSR theme flash with cookie storage or a custom server-side source.
Last updated on
Cookie storage
Since v0.7.0The simplest way to eliminate SSR theme flash. Use storage="cookie" with @wrksz/themes/next - the provider reads the cookie server-side automatically, no boilerplate required:
import { ThemeProvider } from "@wrksz/themes/next";
export default function RootLayout({ children }: { children: React.ReactNode }) {
return (
<html lang="en" suppressHydrationWarning>
<body>
<ThemeProvider
attribute="class"
defaultTheme="dark"
storage="cookie"
disableTransitionOnChange
>
{children}
</ThemeProvider>
</body>
</html>
);
}Theme changes are written to document.cookie automatically. On subsequent requests the server reads the cookie via cookies() from next/headers and injects the correct class before the first paint.
Flash may still appear in Next.js development mode - this is expected. Next.js dev mode does not fully replicate SSR behavior. The flash disappears in production builds.
Cookie storage does not support cross-tab theme sync. If you need it, use the initialTheme approach below with localStorage.
Custom server-side source
Use initialTheme to initialize the theme from any server-side source (database, session, cookie) on every mount. The user can still call setTheme - use onThemeChange to persist the change back.
import { ThemeProvider } from "@wrksz/themes/next";
import { getUserTheme, saveUserTheme } from "@/lib/user";
export default async function RootLayout({ children }) {
const userTheme = await getUserTheme(); // "light" | "dark" | null
return (
<html lang="en" suppressHydrationWarning>
<body>
<ThemeProvider
initialTheme={userTheme ?? undefined}
onThemeChange={saveUserTheme}
>
{children}
</ThemeProvider>
</body>
</html>
);
}initialTheme also writes to storage on mount, so setTheme and cross-tab sync continue to work normally.
Priority
When both initialTheme and a stored value are present, initialTheme wins on every mount. This ensures the server-side value is always applied on page load.