Theme Provider
Theming and dark mode, without the flash.
ThemeProvider owns the active theme. It applies the theme class to <html>,
persists the choice to storage, optionally follows the OS preference, and injects
an inline script that sets the theme before first paint so there's no flash.
Usage
Wrap your app once, as high as possible — at your app's root, inside <body>.
The example below uses Next.js's root layout; for the equivalent file in Vite,
React Router / Remix, TanStack Start, and Astro, see the
Framework notes in Installation.
Read and change the theme anywhere below it with useTheme.
For building a toggle, see Dark Mode.
Nesting ThemeProvider is safe — inner providers are a passthrough. Only the outermost one owns state, so you can use
a nested provider purely to set forcedTheme on a subtree.
Props
Custom theme names
themes plus value let you ship themes beyond light/dark. value maps each
name to the class written on <html>:
Define the matching token overrides for .theme-sepia in your stylesheet — see
Theming.
Preventing flash
The provider renders a tiny synchronous <script> that reads the stored theme
and sets the class before the page paints. That's why <html> needs
suppressHydrationWarning: the script intentionally changes one attribute before
React hydrates. The first post-mount render is skipped so it can't re-introduce a
flash from the hydration default.