Skip to content
HHydro UIdocs
Navigate
ComponentsSwitch
ImplementedForms / settings

Switch

Expose an immediate binary setting with native switch semantics.

Interactive

Try it

checked, disabled, as, label
Notifications
Live previewReady
MarkupStateEvents
<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

Fixture exampleSource-backed
<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/propertyMeaning
checkedCommitted boolean value; the source of truth and reflected by the write path.
disabledPrevents interaction and disables the native form control.
requiredRequires the switch to be checked during native form validation.
nameNative form field name.
valueNative submitted value; defaults to the browser checkbox value when omitted.
formAssociates the control with a form by ID, including when outside the form.
asRendering mode: native (default) or button. as="button" opts into the button variant.
aria-labelAccessible name when no visible projected name is suitable.
aria-labelledbyID reference for an accessible name.
aria-describedbyID 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 } in event.detail.

States and styling

StateContract and styling guidance
Default / uncheckeddata-state="unchecked"; use neutral surface and border aliases.
HoverUse --hui-color-interactive-hover without changing semantics.
ActiveUse --hui-color-interactive-active.
FocusPreserve the native focus behavior or provide a visible ring with --hui-color-focus-ring and --hui-size-focus-ring.
Checkeddata-state="checked" and aria-checked="true"; use --hui-color-interactive.
DisabledNative disabled or aria-disabled="true"; use --hui-color-interactive-disabled.
ErrorNo separate error state is implemented. Consumers may use aria-invalid="true" with associated error text and must not rely on color alone.
State channel

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.
  • required is 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>