Switch
Expose an immediate binary setting with native switch semantics.
Try it
<hui-switch id="playground-switch" name="notifications" value="enabled">
<span>Notifications</span>
</hui-switch>- data-state
- Waiting for enhancement
No component events yet.
Usage
Use hui-switch for an immediate binary setting. It exposes the switch state on the host and renders a native checkbox by default. Set as="button" when a button-based switch is needed; the button variant keeps form submission through a visually-hidden native checkbox.
Do not use it for mutually exclusive choices (use a radio group), multiple independent choices (use a checkbox group), or a command (use a button without the switch role).
The library ships a minimal base control style in components.css for the switch track, thumb, toggle-button variant, focus ring, and state affordances. Consumers can override it and should use the Layer 2 aliases from src/styles/tokens.css.
Disabled native switches keep an explicit token-colored thumb in both checked and unchecked states so the control remains visibly understandable without implying that it is interactive.
Anatomy
Native variant (default, or as="native")
- Host:
hui-switch - Label part:
[data-part="label"] - Native control:
input[type="checkbox"][role="switch"] - Label content: default slot
- State mirror: host
data-state="checked|unchecked"
Button variant (as="button")
- Host:
hui-switch - Button control:
button[role="switch"] - Form control: visually-hidden
input[type="checkbox"][data-hui-form-input] - Label content: default slot inside the toggle button
- State mirror: host
data-state="checked|unchecked"
The button variant is visually a single toggle button. It remains a switch semantically through role="switch" and aria-checked; use a regular button for commands instead of hui-switch.
Examples
<section aria-labelledby="switches-h">
<h2 id="switches-h">Preferences</h2>
<form id="preferences">
<hui-switch id="email-switch" name="email" value="enabled">
<b>Email</b> notifications
</hui-switch>
<hui-switch name="dark-mode" value="enabled" checked>
Dark mode
</hui-switch>
<hui-switch id="unavailable-mode" name="unavailable-mode" value="enabled" disabled>
Unavailable mode
</hui-switch>
<hui-switch name="locked-mode" value="enabled" checked disabled>
Managed by administrator
</hui-switch>
<hui-switch id="compact-switch" as="button" name="compact-mode" value="enabled">
Compact mode
</hui-switch>
</form>
</section>API reference
| Attribute/property | Meaning |
|---|---|
checked | Committed boolean value; the source of truth and reflected by the write path. |
disabled | Prevents interaction and disables the native form control. |
required | Requires the switch to be checked during native form validation. |
name | Native form field name. |
value | Native submitted value; defaults to the browser checkbox value when omitted. |
form | Associates the control with a form by ID, including when outside the form. |
as | Rendering mode: native (default) or button. as="button" opts into the button variant. |
aria-label | Accessible name when no visible projected name is suitable. |
aria-labelledby | ID reference for an accessible name. |
aria-describedby | ID reference for an accessible description. |
State is changed through the host attribute (toggleAttribute("checked")) or by interacting with the rendered control. The checked attribute remains the source of truth.
Events:
hui-checked-change: emitted when the committed checked value changes, with{ checked: boolean }inevent.detail.
States and styling
| State | Contract and styling guidance |
|---|---|
| Default / unchecked | data-state="unchecked"; use neutral surface and border aliases. |
| Hover | Use --hui-color-interactive-hover without changing semantics. |
| Active | Use --hui-color-interactive-active. |
| Focus | Preserve the native focus behavior or provide a visible ring with --hui-color-focus-ring and --hui-size-focus-ring. |
| Checked | data-state="checked" and aria-checked="true"; use --hui-color-interactive. |
| Disabled | Native disabled or aria-disabled="true"; use --hui-color-interactive-disabled. |
| Error | No separate error state is implemented. Consumers may use aria-invalid="true" with associated error text and must not rely on color alone. |
Attributes are the source of truth. Style derived state with data-state, ARIA attributes, and the --hui-* token aliases.
Accessibility and keyboard support
- Native variant follows native checkbox behavior; Space toggles the switch.
- Button variant toggles with Space; Enter does not toggle it.
- A checked control submits its
name/value; an unchecked control submits nothing. requiredis passed through to the active native form control.
SSR and forms
SSR writes resolved aria-checked, checked, disabled, required, name, value, and data-state attributes. The native checkbox variant remains form- and keyboard-functional without JavaScript. The button variant remains a real button for its visible interaction and includes a native hidden checkbox for form submission, but its state is static without JavaScript. The checked attribute is written explicitly so state survives happy-dom serialization and client adoption.
Code
<link rel="stylesheet" href="./styles/tokens.css" />
<link rel="stylesheet" href="./styles/a11y.css" />
<link rel="stylesheet" href="./styles/components.css" />
<hui-switch name="email" value="enabled"> Email notifications </hui-switch>
<hui-switch name="dark-mode" value="enabled" checked> Dark mode </hui-switch>
<hui-switch as="button" name="compact" value="enabled">
Compact mode
</hui-switch>
<hui-switch id="playground-switch" name="notifications" value="enabled">
<span>Notifications</span>
</hui-switch>