Theme toggle
A button that switches the page between the light and dark themes.
import '@usezeno/tokens/css';
import '@usezeno/core/web-components';
Examples
Basic
This button changes the theme of the whole page, not only this example. It writes data-theme="light" or data-theme="dark" on the <html> element. A toggle without a theme starts as system, and it removes data-theme from <html> when it is added to the page.
This example changes the theme of this whole site while it is on the page. Reload the page to put the site back in step.
<zeno-theme-toggle></zeno-theme-toggle>
Variants
Each toggle changes the theme of the whole page. The toggles do not follow each other.
This example changes the theme of this whole site while it is on the page. Reload the page to put the site back in step.
<zeno-theme-toggle variant="default"></zeno-theme-toggle>
<zeno-theme-toggle variant="minimal"></zeno-theme-toggle>
<zeno-theme-toggle variant="outlined"></zeno-theme-toggle>
Sizes
Each toggle changes the theme of the whole page.
This example changes the theme of this whole site while it is on the page. Reload the page to put the site back in step.
<zeno-theme-toggle size="sm"></zeno-theme-toggle>
<zeno-theme-toggle size="md"></zeno-theme-toggle>
<zeno-theme-toggle size="lg"></zeno-theme-toggle>
With the system option
With show-system the button goes through light, dark and system. This also changes the theme of the whole page. The toggle event carries the chosen preference, and theme-change carries the theme that is now in effect.
This example changes the theme of this whole site while it is on the page. Reload the page to put the site back in step.
<zeno-theme-toggle show-system></zeno-theme-toggle>
<p data-result>Preference: system</p>
document.querySelector('zeno-theme-toggle').addEventListener('toggle', event => {
document.querySelector('[data-result]').textContent = 'Preference: ' + event.detail.theme;
});
Attributes and properties
| Property | Attribute | Type | Default | Description |
|---|---|---|---|---|
theme | theme | ThemePreference | 'system' | The chosen theme. system follows the operating system and leaves the
document without a data-theme attribute. |
size | sizereflects | 'sm' | 'md' | 'lg' | 'md' | |
variant | variantreflects | 'default' | 'minimal' | 'outlined' | 'default' | |
animated | animatedreflects | boolean | true | |
showSystem | show-systemreflects | boolean | false | |
loading | loadingreflects | boolean | false | |
testId | string | Test ID for automated testing From ZenoElement. |
Methods
| Method | Description |
|---|---|
toggle(): void | Toggle theme |
focus(): void | Focus the component or its first focusable element From ZenoElement. |
blur(): void | Blur the component or its focused element From ZenoElement. |
Events
| Event | Detail | Description |
|---|---|---|
theme-change | { theme: ('light' | 'dark') } | The theme in effect changed. |
toggle | { theme: ThemePreference } | The user changed the preference. |
Slots
This element has no slots.
CSS parts
| Part |
|---|
base |
moon |
sun |
system |
CSS custom properties
This element documents no custom properties of its own. Style it through its parts and through the tokens it reads.
The element's own source reads no tokens.
Types
type ThemePreference = ThemeName | 'system';
Accessibility
Keyboard
| Key | What it does |
|---|---|
| Tab | Moves focus to the button. |
| EnterSpace | Changes the theme. With show-system it goes to the next of light, dark and system. |
Forms
This element is not a form control. It adds nothing to a form's data.
Notes
- The control is a native
<button>. Itsaria-labelis “Theme: light”, “Theme: dark” or “Theme: System (currently light)”. Anaria-labelon the element replaces that text. - The button has
aria-pressed="true"while the dark theme is in effect. - While the preference is
system, the element follows the operating system and updates when the system theme changes. - With
prefers-reduced-motion: reducethe hover movement and the loading rotation are turned off.
Tests and known gaps
- No tests of its own. The only check is that the element registers and renders (
smoke.test.ts). - Not checked with axe-core.
- Has no Storybook story.
9 of the 16 properties, methods, events, slots and parts above have no description in the source
- the property
size - the property
variant - the property
animated - the property
showSystem - the property
loading - the part
base - the part
moon - the part
sun - the part
system
Known gaps:
- The button shows no icon. It asks for the icons
sunandmoon, and neither is in the icon registry. - The element does not read the theme that the page already has. When it connects, it writes its own
themeto<html>. With the defaultsystem, this removes adata-themethat the page set before. - Two toggles on one page do not stay in step. A toggle does not notice when another toggle, or the page, changes
data-theme. - The choice is not saved. After a reload the theme is
systemagain unless the page stores the value and setsthemeitself. - The button name changes with the state, and
aria-pressedreports the state as well. A screen reader can read “Theme: dark, pressed”. - The button names are fixed English text. The only way to change them is one
aria-labelon the element, which then stays the same in every state. animatedis on by default and is a Boolean attribute, so HTML cannot turn it off. Set theanimatedproperty tofalsefrom script.- While
loading, the button ignores clicks and keys, but it is not disabled and has noaria-busy. It still takes focus and reads as a normal button.