Theme Provider
Supplies theme context and drives the light/dark class on the document.
ThemeProvider holds the current theme — system, light, or dark — persists
it to localStorage, and toggles the dark class on <html> so tokens resolve
correctly. Wrap your app root in it once; anything that reads or sets the theme
does so through the useTheme hook it exposes.
Theme
<ThemeProvider>
<ThemeToggle />
</ThemeProvider>When theme is system, the provider follows the OS preference live and
updates as it changes. Setting light or dark pins the choice and stores it.
Theme changes are instant. The provider disables CSS transitions for the frame
it swaps the dark class, so components with colour transitions don't fade
between themes one by one. See Motion.
useTheme
import { useTheme } from '@base-org/bds-web/product/theme-provider';
const { theme, setTheme, resolvedTheme } = useTheme();theme is the user's choice (including system), resolvedTheme is the
light or dark actually applied, and setTheme changes it. Calling
useTheme outside a ThemeProvider throws.
When to use
Use ThemeProvider once at the app root in any app that supports light and
dark mode.
To let the reader pick a theme, render a Theme Toggle inside it.
Usage
Do
Render exactly one ThemeProvider at the root. It owns the dark class on
<html>, and nesting a second one gives you two sources of truth.
Don't
Toggle the dark class or write to the theme key yourself. Go through
setTheme so the stored value and the applied class stay in sync.
Props
ThemeProvider takes a single prop, children. The active theme is read from
localStorage and the OS colour-scheme preference, not from props.
Accessibility
ThemeProvider defaults to system, so a reader who has set a dark OS
preference gets dark mode without touching anything.
ThemeProvider applies the dark class in an effect after the first render, so
on its own a dark-mode reload briefly paints light. To avoid the flash, add a
small inline script to <head> that reads the same theme key from
localStorage and adds the dark class before paint (falling back to
prefers-color-scheme for system or no stored value). ThemeProvider then
takes over after hydration.