Switch from @prepared911/ui/switch is a Radix switch rendered with a visible label. The primitive handles the switch role, keyboard toggling, and state; your job is to keep the label stable, make on/off readable beyond color, and explain read-only states.
What the component handles
Role assignment. Exposes role="switch" with aria-checked.
Keyboard toggle. Space and Enter toggle the state.
Label association. Children render as the paired label via htmlFor + id.
What you must provide
Stable labels. Keep the label fixed (e.g. "Enable notifications"). Don't flip the label text to reflect state—the role="switch" already announces on/off.
Non-color on/off cue. Keep the thumb position, an icon, or an outline change as a visual state signal so color-blind users can tell on from off.
Read-only explanations. If a switch is locked (policy, permissions), pair it with inline copy or a tooltip that reveals the reason.
Keyboard behavior
Tab / Shift+Tab move focus to the switch.
Space / Enter toggle the switch.
Disabled switches are skipped in focus order.
Semantics and roles
role="switch" with aria-checked="true" or "false".
aria-describedby when helper text is present.
Screen reader announcements
Because a switch represents a persistent setting, announce state changes as naturally as the OS does. If toggling the switch triggers a visible status message ("Notifications enabled"), use a polite live region so the confirmation is not announced twice.
SwitchVisual
SwitchVisual is a non-interactive, always aria-hidden paint of the switch. It must not carry selection semantics alone—the parent widget owns aria-checked (for example MenuItemSwitch as menuitemcheckbox). Do not use it as a standalone toggle. For the full menu pattern (one interactive widget per row, decorative indicators), see Interactive MenuItem children.
Known caveats
Not for actions. Switches must represent a persistent on/off setting. If the control fires a one-shot action, use a Button instead.
Not for required choices. A switch represents a binary state; if the question is "Do you agree?", use a Checkbox that supports the required / error path.