Toggle
A switch for binary on and off settings. It is a native checkbox exposed with the switch role, so it submits a form value like any other field.
Import
import { Toggle } from "@hyzer-labs/ui"Demo
Toggle vs Checkbox
Toggle when a setting reads as on or off, like a preference. It renders role="switch", which screen readers announce as on or off. Use Checkbox for selections from a list, multi-select membership,
or the indeterminate select-all pattern.let notifications = $state(true);
<Toggle name="notifications" label="Round notifications" bind:checked={notifications} />description and error are announced with the switch: both
chain into aria-describedby, on their own row below the switch-and-label
pair. Error and disabled are also field states. The wrapper's data-state reflects
them, and error wins.
Saves your scorecard after every hole.
Location access was denied.
<Toggle
name="autosave"
label="Auto-save scorecards"
description="Saves your scorecard after every hole."
/>
<Toggle name="location" label="Share location with your card" error="Location access was denied." />
<Toggle name="terms" label="Play by PDGA rules" required />
<Toggle name="premium" label="Live scoring (premium)" disabled />
<Toggle name="metric" label="Metric distances" disabled checked />Props
| Name | Type | Default | Note |
|---|---|---|---|
name | string | — | Required. Form field name. |
label | string | — | Required. Always in the DOM; sr-only with hideLabel. |
checked | boolean | false | Bindable. |
value | string | — | Submitted value when on. |
description | string | — | Help text on its own row. |
error | string | — | Inline error message; sets the error state. |
required | boolean | false | |
disabled | boolean | false | |
hideLabel | boolean | false | |
class | string | — | Merged after the hz-field hz-field--toggle classes. |
Theme hooks
What this component promises your CSS. The reference theme styles exactly these — from @layer hz-theme, so your unlayered rules win. See Styling Components for the how.
Root class: .hz-field hz-field--toggle
Overriding this needs extra care
.hz-field--toggle input.hz-toggle — the track and thumb — is the one rule in the reference theme shipped outside @layer hz-theme, on purpose: headless, Toggle is a bare native checkbox, so this rule needs to out-rank the component's own scoped structural reset unconditionally, and a layer can only lose to an unlayered rule regardless of specificity. It sits at a raw (0,2,1) specificity. A normal override written inside a layer — or even an unlayered rule that ties on specificity and loses on source order — silently does nothing; the toggle keeps its default look with no error. To win reliably, give your override enough specificity to clear (0,2,1) outright, e.g. by scoping it under your own theme's root class: .your-theme .hz-field--toggle input.hz-toggle { … }. See the Terminal example theme for a worked example (theme/examples/terminal/components/toggle.css), which does exactly this. The same applies to the --hz-toggle-width / --hz-toggle-height custom properties below — they're declared directly on that selector, so setting them from a lower-specificity or losing rule never reaches the element.Data attributes
| Hook | Values | Styles |
|---|---|---|
data-state (on the root) | 'default' | 'error' | 'disabled' | The universal field state hook, as on every field. Precedence is fixed: error beats disabled. |
data-state (on input.hz-toggle) | 'on' | 'off' | A second data-state nested inside the root’s, with a disjoint vocabulary — this is the stable hook for the track and thumb. It exists rather than relying on :checked because the toggle rules must win the specificity fight described above, and an attribute selector composes into them cleanly. |
Custom properties
| Hook | Values | Styles |
|---|---|---|
--hz-toggle-width | <length> — default 2.5rem | Track width, and the distance the thumb travels. |
--hz-toggle-height | <length> — default 1.5rem | Track height. The thumb derives from it (height minus a 2px inset all round), so there is no separate thumb knob — and the travel stays correct under any override. |
Part classes
| Hook | Values | Styles |
|---|---|---|
.hz-field-label | child element | The label. |
.hz-field-required | child element | The required marker. |
.hz-field-description | child element | The hint text. |
.hz-field-error | child element | The error message. |
.hz-toggle | the checkbox input | The track. Its ::before is the thumb, so the thumb has no class of its own. |
Accessibility
Toggle renders an <input type="checkbox" role="switch"> associated with its label via id/for. Screen readers announce it as a switch, while the native checked state, keyboard behavior (Space toggles, Enter submits the form), and form participation all come from the platform.
description and error chain into aria-describedby, description first. required sets aria-required, and an error sets aria-invalid.
References: APG Switch pattern · MDN: switch role