The bare switch: track, knob, states, nothing else. It is to Toggle what
Checkbox is to CheckboxInput.
Reach for Toggle for an ordinary form field — it owns the label, its layout and its variants.
Reach for Switch when the label already exists somewhere else (a table column heading, a toolbar)
or when composing a new labelled variant.
import { Switch } from "@uxf/ui/switch";
<Switch aria-label="Notifications" name="notifications" onChange={setValue} value={value} />;
CSS: @uxf/ui/css/switch.css.
Switch renders a control with no text of its own, so it has no accessible name unless one is
given. Pass aria-label, or aria-labelledby pointing at the element that already names it.
Both are optional, and nothing enforces that one is present: requiring "one of them" through a
union type would break the Omit<…Props, …> composition the @uxf/form wrappers rely on, because
Omit does not distribute over a union. Naming the control is the caller's job.
| Prop | Type | Note |
|---|---|---|
value | boolean | undefined | |
onChange | (value: boolean) => void | |
name | string | |
aria-label / aria-labelledby | string | Accessible name, see above |
isDisabled | boolean | Not focusable, not submitted |
isReadOnly | boolean | Focusable and announced, value locked |
isInvalid | boolean | Red outline, red track when on |
size | "sm" | "default" | |
id, className, style |
A switch has only on and off. aria-checked="mixed" is valid on checkbox and invalid on switch,
and the visual promises a binary that flips right now, which a half state cannot honour. Where a
tri-state is wanted — a parent over N children, "all notifications" — the control is a checkbox:
use CheckboxInput, which supports indeterminate and announces it as mixed. A row of switches
with one checkbox in it looks inconsistent; a switch claiming to be half on is wrong.