Theme Provider
React API for theming — the Theme provider, useTheme hook, and ThemeSwitcher toggle.1<ThemeSwitcher />
This page documents the React API for theming: the Theme provider component, the useTheme hook, and the ThemeSwitcher button. For the theming system itself — design tokens, colors, spacing, and scoped theming in depth — see the Theme overview.
Theme manages light/dark mode (including the system preference), persists the user's choice to localStorage, and applies the style, accentColor, and grayColor attributes that drive Apsara's design tokens. It injects a small inline script so the correct theme is applied before first paint, avoiding a flash of the wrong theme.
Anatomy
Wrap your application with the provider, then read or change the theme anywhere below it:
1import { Theme, ThemeSwitcher, useTheme } from "@raystack/apsara";23<Theme defaultTheme="system" accentColor="indigo">4 <App />5 <ThemeSwitcher />6</Theme>
API Reference
Theme
The provider component. Rendered at the root it manages the document-level theme; rendered inside another Theme it becomes a scoped provider that overrides theme attributes for its subtree only (see scoped theming).
Prop
Type
useTheme
Reads the theme state from the nearest Theme ancestor and returns a setter to change it.
1import { useTheme } from "@raystack/apsara";23function MyComponent() {4 const { theme, setTheme, resolvedTheme } = useTheme();56 return (7 <button onClick={() => setTheme(resolvedTheme === "dark" ? "light" : "dark")}>8 Current theme: {theme}9 </button>10 );11}
The hook accepts an optional options object:
Prop
Type
And returns:
Prop
Type
ThemeSwitcher
A ready-made icon button that toggles between light and dark. It calls useTheme internally, so it must render inside a Theme provider.
Prop
Type
Slots
Every rendered part carries a stable data-slot attribute for styling and testing:
| Slot | Element |
|---|---|
theme-script | The inline <script> that applies the theme before first paint |
theme-scope | The wrapper <div> rendered by a nested (scoped) Theme |
theme-switcher | The ThemeSwitcher button |
Examples
Theme Switcher
ThemeSwitcher toggles the nearest provider — here, the whole docs site. The size prop sets the button's width and height in pixels.
1<Flex gap={5} align="center">2 <ThemeSwitcher size={24} />3 <ThemeSwitcher size={30} />4 <ThemeSwitcher size={40} />5</Flex>
Forced theme
A nested Theme with forcedTheme pins a subtree to one theme, regardless of the page theme.
1<Flex gap={5}>2 <Theme forcedTheme="light">3 <Callout type="normal">Always light</Callout>4 </Theme>5 <Theme forcedTheme="dark">6 <Callout type="normal">Always dark</Callout>7 </Theme>8</Flex>
Accessibility
Themerenders no visible UI of its own — only an inline script, and a wrapper<div>when nested.ThemeSwitcheris a native button with a descriptivearia-label("Switch to light theme" / "Switch to dark theme"), so it works with keyboards and screen readers out of the box.- With
enableColorScheme(default), the provider sets the CSScolor-schemeproperty so built-in browser UI (inputs, scrollbars) matches the active theme. defaultTheme="system"(default) respects the user's OS-levelprefers-color-schemepreference.