Ready-made control over the theme store: call
initTheme() once at startup and drop a ThemeToggle anywhere. Two variants:
cycle(default) — oneIconButtoncycling light → dark → system, icon showing the current mode (sun/moon/monitor). For header chrome.segmented— a three-waySegmentedControl. For settings pages.
Every instance reads the store reactively, so multiple toggles (header + settings) stay in sync, and the mode persists via the store's localStorage key.
<script lang="ts">
import { initTheme, ThemeToggle } from "@kenn-io/kit-ui";
initTheme(); // once, at app startup
</script>
<ThemeToggle />
<!-- header icon button -->
<ThemeToggle variant="segmented" />
<!-- settings selector -->| Prop | Type | Default | Notes |
|---|---|---|---|
variant |
"cycle" | "segmented" |
"cycle" |
|
size |
"sm" | "md" |
"md" |
Cycle variant's IconButton size |
lightLabel / darkLabel / systemLabel |
string |
"Light" / "Dark" / "System" |
Segment labels + the {mode} value in cycleLabel |
cycleLabel |
string |
"Change theme (current: {mode})" |
aria-label template for the cycle button — action-oriented; {mode} and {nextMode} are replaced |
ariaLabel |
string |
"Theme mode" |
Group label for the segmented variant's radiogroup |
block |
boolean |
false |
Segmented variant stretches to the container |
class |
string |
"" |
- The component only sets the mode — high-contrast is a separate,
orthogonal flag (
setHighContrast); expose it as its own switch in settings UIs. initTheme()is what restores the persisted mode at startup and applies the initial root classes (and configures a custom storage key). Without it the toggle still works andsetThemeModestill writes to the default key — but nothing is restored on the next load until something callsinitTheme().