Theme Toggle
Switches the page between light and dark themes.
Installation
pnpm dlx shadcn@latest add @paneui/theme-toggleUsage
Examples
Motion
The reveal uses the View Transition API and starts at the click point, or at the button's centre for keyboard presses. With reduced motion, or without the API, the theme swaps instantly and the icon only cross-fades.
Persistence
The choice is saved to localStorage under storageKey ("light" or "dark"); choosing System removes the key, and no key means the page follows the OS, including OS changes while it is open. A theme-change window event (THEME_CHANGE_EVENT) fires, so several toggles stay in sync, and other tabs follow through the storage event.
Labels
The button is named by the locale: switchToLightTheme or switchToDarkTheme, themeCycle(current, next) with themeLight, themeDark and themeSystem in the tri-state mode, and toggleTheme before the theme is known. An aria-label prop wins.
Pre-paint script
Inline getThemeScript() in a <script> at the top of <head> so the first paint has the right theme: <script dangerouslySetInnerHTML={{ __html: getThemeScript() }} /> (pass your storageKey if you changed it). It sets the .dark class and color-scheme, and with no stored value keeps following OS changes even before the page hydrates.
ThemeToggle
Round 32px button that flips the .dark class on <html>. Also accepts every prop of button.
- iconSize= 16
- number
- Sun / moon icon size in px.
- variant= "raised"
- "raised" | "ghost"
- Round raised button, or a 28px ghost toolbar button that matches
size="icon-sm"ghost Buttons. - storageKey= "theme"
- string
localStoragekey for the saved theme.- duration= 560
- number
- Reveal duration in ms.
- onThemeChange
- (theme: "light" | "dark") => void
- Called after the theme changes.
- modes= "binary"
- "binary" | "tri"
binaryflips light and dark.tricycles light, dark and system and shows the stored choice (a monitor icon for system).
| Prop | Type | Default | Description |
|---|---|---|---|
| iconSize | number | 16 | Sun / moon icon size in px. |
| variant | "raised" | "ghost" | "raised" | Round raised button, or a 28px ghost toolbar button that matches size="icon-sm" ghost Buttons. |
| storageKey | string | "theme" | localStorage key for the saved theme. |
| duration | number | 560 | Reveal duration in ms. |
| onThemeChange | (theme: "light" | "dark") => void | — | Called after the theme changes. |
| modes | "binary" | "tri" | "binary" | binary flips light and dark. tri cycles light, dark and system and shows the stored choice (a monitor icon for system). |
- data-mode
- The current mode when
modes="tri".
| Data attribute | Description |
|---|---|
| data-mode | The current mode when modes="tri". |
useTheme
Returns { theme, resolvedTheme, systemTheme, setTheme }. theme is the stored choice ("system" when nothing is stored), resolvedTheme the theme on the page. All are null until mounted.
- storageKey= "theme"
- string
localStoragekey.- duration= 560
- number
- Reveal duration in ms.
- onThemeChange
- (theme: "light" | "dark") => void
- Called after the theme on the page changes.
- setTheme
- (theme: "light" | "dark" | "system", options?: { origin?: { x: number; y: number } }) => void
- Returned. Store a choice and reveal the result from
origin;"system"removes the key.
| Prop | Type | Default | Description |
|---|---|---|---|
| storageKey | string | "theme" | localStorage key. |
| duration | number | 560 | Reveal duration in ms. |
| onThemeChange | (theme: "light" | "dark") => void | — | Called after the theme on the page changes. |
| setTheme | (theme: "light" | "dark" | "system", options?: { origin?: { x: number; y: number } }) => void | — | Returned. Store a choice and reveal the result from origin; "system" removes the key. |
useThemeToggle
Returns { theme, setTheme, toggle }. theme is null until mounted, then follows the .dark class.
- storageKey= "theme"
- string
localStoragekey.- duration= 560
- number
- Reveal duration in ms.
- onThemeChange
- (theme: "light" | "dark") => void
- Called after the theme changes.
- setTheme
- (theme: "light" | "dark", options?: { origin?: { x: number; y: number } }) => void
- Returned. Switch to a theme, revealing from
origin(defaults to the viewport centre). - toggle
- (options?: { origin?: { x: number; y: number } }) => void
- Returned. Switch to the other theme.
| Prop | Type | Default | Description |
|---|---|---|---|
| storageKey | string | "theme" | localStorage key. |
| duration | number | 560 | Reveal duration in ms. |
| onThemeChange | (theme: "light" | "dark") => void | — | Called after the theme changes. |
| setTheme | (theme: "light" | "dark", options?: { origin?: { x: number; y: number } }) => void | — | Returned. Switch to a theme, revealing from origin (defaults to the viewport centre). |
| toggle | (options?: { origin?: { x: number; y: number } }) => void | — | Returned. Switch to the other theme. |