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.

ThemeProvider is a deprecated alias of Theme and will be removed in a future major release. Use Theme instead.

Anatomy

Wrap your application with the provider, then read or change the theme anywhere below it:

1import { Theme, ThemeSwitcher, useTheme } from "@raystack/apsara";
2
3<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";
2
3function MyComponent() {
4 const { theme, setTheme, resolvedTheme } = useTheme();
5
6 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:

SlotElement
theme-scriptThe inline <script> that applies the theme before first paint
theme-scopeThe wrapper <div> rendered by a nested (scoped) Theme
theme-switcherThe 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

  • Theme renders no visible UI of its own — only an inline script, and a wrapper <div> when nested.
  • ThemeSwitcher is a native button with a descriptive aria-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 CSS color-scheme property so built-in browser UI (inputs, scrollbars) matches the active theme.
  • defaultTheme="system" (default) respects the user's OS-level prefers-color-scheme preference.