Components / Actions
ThemeSwitch
Four smooth ways to move between light and dark appearance.
Install
npx shadcn@latest add https://irisui.dev/r/theme-switch.jsonimport { ThemeSwitch } from "@/components/iris/theme-switch/theme-switch";Preview
ThemeSwitch
A light/dark toggle whose sun and moon turn into each other, with four named variants (reveal, eclipse, split, rise) for the page transition your app runs.
When to use
- The appearance toggle in a top bar, settings row or docs header.
- When you want the page change to feel tied to the button — the trigger element is handed to your handler so a view transition can start from it.
- For a three-way light / dark / system choice inside an account menu, use
UserMenu(showTheme).
Usage
import { ThemeSwitch } from "@/components/iris/theme-switch/theme-switch";
<ThemeSwitch
theme={theme}
iconOnly
variant="reveal"
onThemeChange={(next, variant, trigger) => {
if (!document.startViewTransition) return setTheme(next);
document.startViewTransition(() => setTheme(next));
}}
/>;
Props
| Prop | Type | Default | Description |
|---|---|---|---|
theme |
"light" | "dark" |
— | Current theme (required). The component is controlled. |
onThemeChange |
(next, variant, trigger: HTMLElement) => void |
— | Called with the opposite theme, the variant, and the button element (required). Apply the theme here. |
variant |
"reveal" | "eclipse" | "split" | "rise" |
"reveal" |
Names the page transition and sets a matching icon nudge. The component does not run the page transition itself. |
label |
string |
"Switch to {next} mode" |
Accessible name. |
iconOnly |
boolean |
false |
Hides the visible "Switch theme" text. |
Notes
- Renders a
Button(secondary, sm) witharia-pressedtrue in dark mode anddata-theme={theme}on the button, so the button itself paints in the theme it shows. - The icon swap is skipped for the first painted frames, so a page that loads in dark mode never spins its switch.
- A full-page view transition snapshots the whole document: keep it short and skip it for reduced motion. The icon turn already becomes a fade under reduced motion.