import { ThemeSwitcher } from "@elabs-ai/components-ui";npm install @elabs-ai/components-tokens @elabs-ai/components-uiPrompt for your coding agent
Paste it into Claude Code, Cursor, Codex or any other coding agent. Text in [brackets] is yours to fill in.
Add the brand-ui ThemeSwitcher component (from @elabs-ai/components-ui) to this project. 1. Read https://elabs-ai.com/llms.txt first: it maps every package and the rules. If you can use MCP servers, connect https://elabs-ai.com/mcp and use its search, docs and tokens tools. If not, run the same lookups in the terminal: `npx -y @elabs-ai/components-cli search "<what you need>"` and `npx -y @elabs-ai/components-cli docs <Component>`. 2. Look ThemeSwitcher up before writing code: `npx -y @elabs-ai/components-cli docs ThemeSwitcher` prints its real props, variants, what it pairs with and what to avoid. 3. If @elabs-ai/components-ui is not installed yet: `pnpm add @elabs-ai/components-tokens @elabs-ai/components-ui` (or `npm install @elabs-ai/components-tokens @elabs-ai/components-ui`). If this is the first brand-ui package in the project, wire it once: import `@elabs-ai/components-tokens/styles.css` plus the `themes/light.css` and `themes/dark.css` stylesheets in the CSS entry, add one Tailwind `@source` line per installed @elabs-ai package (Tailwind does not scan node_modules, so without it everything renders unstyled), and wrap the app root in `ThemeProvider` from `@elabs-ai/components-tokens`. 4. Use it here: [the screen or file, and what it should show] 5. Rules: use only @elabs-ai/components-* components and the semantic tokens — no raw colours, no raw font sizes, no arbitrary Tailwind values. Look up each component's real props with the docs tool before you use it; never guess a prop. 6. Done means: the typecheck passes, `npx -y @elabs-ai/components-cli audit src --strict` reports nothing, and you have opened the app and looked at every screen you touched in the light and the dark theme.
Examples
Dropdown
Dropdown mode — the list form. (More than two themes picks this automatically.)
Toggle No System
Toggle without the System option (light / dark only).
Custom Pair
A custom (non-default) theme pair. ≤2 themes still toggle instead of a dropdown.
Controlled
Controlled mode (#366): the caller owns the preference — including "system" — via `preference`/`onPreferenceChange` instead of the switcher's own `localStorage`-backed state, e.g. a settings panel synced to a server. The label below reflects the plain `useState` living OUTSIDE `ThemeSwitcher`.
Restricted Provider
With Theme Families
Single Mode Family
API
ThemeSwitcher
| Prop | Type | Description |
|---|---|---|
themes | ThemeName[] | Themes to offer, as names. ≤2 → toggle; >2 → dropdown. Defaults to the PROVIDER's registry (ADR 0029) — so an app that registers its own themes gets a working switcher with no prop at all. Pass this only to offer a subset, or to fix the order; names the provider doesn't know are dropped. |
mode | "auto" | "toggle" | "dropdown" | Force presentation; "auto" (default) picks toggle vs dropdown by theme count. |
showSystem | boolean | Offer a "System" option that follows the OS color scheme. Default true. |
effect | ThemeTransitionEffect | Whole-screen reveal effect for the animated switch. Default "polygon". |
size | ButtonSize | Control size. Default "default". |
variant | ButtonProps["variant"] | The trigger button's variant. Default: `"outline"` for the dropdown forms and `"ghost"` for the two-theme toggle (today's behaviour). Pass `"ghost"` when the switcher sits in a row of borderless icon buttons — an app top bar — so it reads as one of them. |
preference | ThemePreference | Controlled preference (#366). When set, the switcher derives its "current" state — including "system" — from this prop instead of its own internal, `localStorage`-backed state, and reports every user pick via `onPreferenceChange` instead of writing its own storage key. Pass this pair when your app's actual source of truth is a different persisted preference (a settings API, a different storage key, a server-synced setting). Omit both for the default, uncontrolled behavior (unchanged). |
onPreferenceChange | (preference: ThemePreference) => void | Called with the new preference on every user pick, when `preference` is controlled. |