Skip to main content

Theme toggle

<zeno-theme-toggle>ActionsSource

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​

PropertyAttributeTypeDefaultDescription
themethemeThemePreference'system'The chosen theme. system follows the operating system and leaves the document without a data-theme attribute.
sizesizereflects'sm' | 'md' | 'lg''md'
variantvariantreflects'default' | 'minimal' | 'outlined''default'
animatedanimatedreflectsbooleantrue
showSystemshow-systemreflectsbooleanfalse
loadingloadingreflectsbooleanfalse
testIdstringTest ID for automated testing From ZenoElement.

Methods​

MethodDescription
toggle(): voidToggle theme
focus(): voidFocus the component or its first focusable element From ZenoElement.
blur(): voidBlur the component or its focused element From ZenoElement.

Events​

EventDetailDescription
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​

KeyWhat it does
TabMoves focus to the button.
EnterSpaceChanges 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>. Its aria-label is “Theme: light”, “Theme: dark” or “Theme: System (currently light)”. An aria-label on 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: reduce the 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 sun and moon, 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 theme to <html>. With the default system, this removes a data-theme that 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 system again unless the page stores the value and sets theme itself.
  • The button name changes with the state, and aria-pressed reports 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-label on the element, which then stays the same in every state.
  • animated is on by default and is a Boolean attribute, so HTML cannot turn it off. Set the animated property to false from script.
  • While loading, the button ignores clicks and keys, but it is not disabled and has no aria-busy. It still takes focus and reads as a normal button.