Switch#

An on/off toggle over a visually hidden native <input type="checkbox"> with role="switch". The native input gives form participation, labelling and the platform's keyboard behavior; the visible control (the track) and thumb are pure styling surfaces. A switch is a form value — a mode you flip without one is a Toggle.

Import#

TSX
import { Switch } from '@sigx/zero/switch';

Switch is a compound with a single member, Switch.Root. It is also re-exported from the @sigx/zero root, together with switchAnatomy.

Usage#

TSX
import { component } from 'sigx';
import { Switch } from '@sigx/zero/switch';

const Notifications = component(({ signal }) => {
    const state = signal({ enabled: true });

    return () => (
        <Switch.Root model={() => state.enabled} name="notify" color="primary">
            Notifications
        </Switch.Root>
    );
});

model={() => state.enabled} binds the checked state both ways — flipping the switch writes state.enabled, and writing state.enabled flips it. Leave the model off and pass defaultChecked to keep the state inside the component; checkedChange fires either way. See Models. The default slot is the label text; with no children the label part is not rendered.

Inside a Field#

TSX
<Field.Root disabled={saving()}>
    <Field.Label>Two-factor authentication</Field.Label>
    <Switch.Root model={() => state.twoFactor}>Require a code at sign-in</Switch.Root>
    <Field.Description>Applies to every device.</Field.Description>
</Field.Root>

Inside a Field.Root the hidden input adopts the field's control id and aria-describedby, and the switch's disabled, invalid and required each derive as the switch's own prop or the field's — the prop wins when set, the field supplies the rest.

Form value#

TSX
<Switch.Root model={() => state.marketing} name="marketing" value="yes">

The hidden input posts value (default on) under name while checked, and nothing while unchecked, exactly as a native checkbox does.

Anatomy#

PartElementStatesFlagsNotes
rootlabelchecked | uncheckeddisabled, focus-visible, invalid, requiredThe label row; the pointer target. Carries the variant axes.
hidden-inputinputThe native checkbox with role="switch", visually hidden and focusable; carries name, value, required, aria-invalid and aria-describedby. Inside root.
controlspanchecked | uncheckeddisabled, focus-visible, invalid, pressed, press-animatingThe track a design system paints. Publishes press feedback. Inside root.
thumbspanchecked | uncheckedThe knob; a recipe moves it on data-state. Inside control.
labelspanchecked | uncheckeddisabledThe label text; rendered only when the default slot is given. Inside root.

Every part carries data-scope="switch" and data-part="<part>". The hidden-input is a real, styleable part: the native input renders so the switch posts pre-hydration, hidden with an inline clip rather than display: none so it stays focusable. See The anatomy contract.

The control declares the invalid flag as well as the root, matching Checkbox: the track is what a design system paints, and reaching it from the root would cost every recipe a descendant selector for a fact the control knows about itself. Press feedback is cross-element: a press anywhere in the label row, or Space on the hidden input, lands on the control, with the --press-* coordinates computed against the track's rect.

Props#

Switch.Root#

PropTypeDefaultDescription
modelbooleanTwo-way binding of the checked state.
defaultCheckedbooleanfalseInitial state when uncontrolled.
checkedChangeevent (checked: boolean)Fires whenever the checked state changes.
namestringForm field name on the hidden input.
valuestring'on'The value the hidden input posts while checked.
requiredbooleanfalseRenders required and data-required; a wrapping Field's required also applies.
invalidbooleanfalseRenders aria-invalid and data-invalid on root and control; a wrapping Field's invalid also applies.
disabledbooleanfalseRenders disabled and data-disabled; a wrapping Field's disabled also applies.
color / size / variant / axes / modsdesign-system vocabularyThe variant axes, rendered as data-* on root.
classstringExtra classes on the root element.

Keyboard#

KeyAction
SpaceToggles, via the native input; the press lands on the control.
TabMoves focus to and from the hidden input; data-focus-visible on root and control while keyboard-focused.

The platform owns the toggle; zero only mirrors the native change event into the model. A screen reader announces the control as a switch that is on or off, from role="switch" and the native checked state.

In the shipped design systems#

Both @sigx/zero-basic and @sigx/zero-daisyui wire color (the eight recommended roles) and size (xsxl) on switch, and both default color to primary, so a bare <Switch.Root> is already tinted and <Switch.Root color="success" size="sm"> is styled in both. Neither wires a variant or any mods on the scope; under a design system's /register import those props are therefore absent. See Typed vocabulary.

The travel is the recipe's: a design system slides the thumb on [data-state="checked"] and fills the control from the color axis. Write the transition against a --duration-* token rather than a literal, so the motion honours prefers-reduced-motion — see Theming.

Checkbox · Toggle · Field