AppThemeToggle
The light/dark switch — one disc, or one button per mode, that flips the whole page with a wave, a circle, a wipe, blinds or a fade.
<app-theme-toggle effect="wave" />A theme toggle is the one control that changes every pixel on the page at once, so the change deserves to be seen: press it and the new theme sweeps across the screen. Dark rises from the bottom, light falls from the top, and the part the edge has passed is already the new theme while the rest is still the old one.
It owns the theme end to end. It reads the stored choice, writes data-theme and data-bs-theme on <html> (which the design system and Bootstrap both read), remembers the choice in localStorage, and runs the switch through the shared engine in @webority/ui-elements. The Razor <app-theme-toggle> and the React <AppThemeToggle> call the same code, so both surfaces store, apply and animate identically.
Playground
Every attribute, live — press the disc to switch this page. Each change re-renders the real tag helper on the server, so the markup underneath is the exact call that produced the disc above it.
Effects
Six ways to cross the screen. Each one here switches this page, so press them in turn. Dark always comes up from the bottom and light down from the top; a circle grows from the disc you pressed.
wavecircleslideblindsfadenoneeffect="none", or when the page already shows the requested theme (dark to auto on a dark system), the switch is instant. Nothing else changes.Variants
icon (default) is one disc that cycles through the modes on each press. segmented lays the modes out side by side, like app-segmented, so each mode is a button of its own and a settings page can show the choice.
Show code
<app-theme-toggle variant="segmented" include-auto="true" storage-key="sc-theme" />
Show code
<app-theme-toggle variant="segmented" effect="circle" light-label="Day" dark-label="Night" storage-key="sc-theme" />
Modes
Two modes by default, light and dark, so every press visibly changes the page. include-auto adds a third, system-following step: light, dark, auto, light.
Show code
<app-theme-toggle include-auto="true" storage-key="sc-theme" />
Setup
The script applies the stored choice when it runs, which is after the page has painted. To avoid a flash of the wrong theme before that, stamp the choice on <html> in an inline script in <head>; the toggle then takes over from that state.
Both sandboxes carry this script; the page you are reading loaded straight into its stored theme.
Show code
<script>
(function () {
var t = localStorage.getItem('theme');
t = t === 'dark' || t === 'auto' ? t : 'light';
var dark = window.matchMedia('(prefers-color-scheme: dark)').matches;
document.documentElement.setAttribute('data-theme', t);
document.documentElement.setAttribute('data-bs-theme', t === 'auto' ? (dark ? 'dark' : 'light') : t);
})();
</script>
Use it when
- One disc in the app chrome (the topbar, the sidebar foot) that switches the whole product
- A settings row that offers light, dark and system (include-auto)
Reach for something else when
- A per-section or per-card theme: the switch is page-wide by design
- Branding colour choices: that is a theme variable, not a mode
Attributes
| Attribute | Type | Default | Description |
|---|---|---|---|
| variant | icon | segmented | icon | One disc that cycles through the modes, or one option per mode laid out like app-segmented. |
| effect | wave | circle | slide | blinds | fade | none | wave | The page-wide effect. An unknown value throws at render. |
| include-auto | boolean | false | Offer a third, system-following mode: light, dark, auto. |
| storage-key | string | "theme" | The localStorage key the choice is kept under. Match it in the pre-paint stamp. |
| duration | int | — | Effect length in ms. Each effect has its own default (wave 1100, circle 700, slide 600, blinds 900, fade 350). |
| label | string | "Theme" | Accessible name and tooltip, shown with the current mode: "Theme: dark". |
| light-label | string | "Light" | The segmented variant's option text for light. |
| dark-label | string | "Dark" | The segmented variant's option text for dark. |
| auto-label | string | "System" | The segmented variant's option text for auto. |
| name | string | — | The segmented variant's field name (what groups its radios). Defaults to a generated one. |
| size | sm | md | lg | xl | md | The disc's glyph size (16 / 20 / 24 / 28px; the disc scales with it) or the segmented strip's size, like app-segmented. |
| tooltip-placement | auto | top | bottom | start | end | auto | Preferred tooltip side; auto picks the side with the most room. |
| class | string | — | Extra classes on the disc. |