Switch
A setting that applies immediately.
Installation
pnpm --filter your-app add "@commenda/pathfinder@workspace:*"Import @commenda/pathfinder/styles.css once at the app root. The stylesheet is precompiled with Tailwind v4; your application does not need Tailwind or source scanning. Event handlers belong in a client component in Next.js App Router.
Usage
import { Switch } from '@commenda/pathfinder/switch';
<Switch
label="Weekly summary"
description="Sent each Monday."
checked={weeklySummary}
onCheckedChange={onWeeklySummaryChange}
/>;| Prop | Type | Default / behavior |
|---|---|---|
label | string | Required stable setting name |
hideLabel | boolean | false; accessible name retained |
description | string | Optional supporting explanation |
checked | boolean | Controlled state |
defaultChecked | boolean | false; uncontrolled initial state |
onCheckedChange | (checked: boolean) => void | Next state; application owns persistence |
disabled | boolean | Disables interaction for the control or group. |
readOnly | boolean | Keeps the current value visible while preventing changes. |
required | boolean | Requires a value for native form validation. |
disabledReason | string | Visible, associated explanation while disabled |
name | string | Name used when the control submits its value with a form. |
value | string | Value submitted when checked; defaults to 'on'. |
uncheckedValue | string | Value submitted when unchecked; omitted when not configured. |
form | string | ID of the form associated with the control. |
id | string | ID of the underlying form input. |
inputRef | Ref<HTMLInputElement> | Access to the underlying form input. |
className | string | Additional class names for the outer layout. |
ref | Ref<HTMLElement> | Access to the interactive root element. |
| Native events and ARIA | Base UI root props | Typed passthrough |
A switch applies immediately. Keep its label the same in both states, such as “Weekly summary”, rather than “Turn on weekly summary”. On a failed asynchronous save, the application reverts the controlled state and explains the failure; this component does not invent persistence or loading/completion states. For form-save behavior use Checkbox, and for non-boolean choices use RadioGroup or SegmentedControl.
Track 36×20px, thumb 16px inset 2px, control elevation and 200ms ease-out movement. Honor reduced motion and RTL; coarse-pointer layouts provide at least a 44px row target without enlarging the visual control.
Examples
Off and on
Description
Disabled states
Read the Figma choice-control rules for design guidance, source discrepancies and accessibility requirements.
Design rules
Figma guidance and reviewed implementation decisions for this component. Rule IDs remain stable for source comments and AI references.
Switch
Source: 199:4, variants 200:5083, anatomy 207:148, guidance 207:184.
- SWITCH-01 — Apply immediately with no separate Save action. Use Checkbox for changes saved later. Never use a switch to choose between two non-boolean options.
- SWITCH-02 — The label names the setting and remains unchanged between states. Show results immediately; if persistence fails, the application reverts the controlled state and explains why. No invented loading/completion status is part of this API.
- SWITCH-03 — Track 36×20px, radius full. Thumb 16px with 2px inset and Elevation/control. Off soft-pearl-400, on blue-700; hover soft-pearl-500/blue-800. Move the thumb 200ms ease-out; turn movement off for reduced motion and reverse travel in RTL. Label starts 8px from track, with 2px top alignment.
- SWITCH-04 — Disabled off uses soft-pearl-100 track with soft-pearl-300 edge; disabled on uses soft-pearl-300 track. Thumb uses soft-pearl-200 without shadow. Keep the label readable with soft-pearl-600.
Implementation decisions and source differences
The complete prop tables are on Checkbox, RadioGroup and Switch. Source rule IDs are also kept in the component implementation comments and exported through llms.txt, llms-full.txt and the Markdown routes.
-
CHOICE-01 — The sheets describe 8px list gaps but some documentation frames place rows 32px apart. Use the documented 8px component-list gap; documentation specimen whitespace is not a new size token.
-
CHOICE-02 — Built-in text is plain, wrapping content. Do not place links, buttons or nested interactive controls inside labels or cards. Disabled reasons are visible descriptions, not tooltip-only explanations on controls removed from keyboard navigation.
-
CHOICE-03 — Visual control size is not the hit target. Coarse-pointer rows provide at least 44px height, while preserving 16px marks and the 36×20px switch track. Cards already exceed this height.
-
CHOICE-04 — Hover/focus are real browser states, not public cosmetic props. Retain native
name,value,form,required,readOnly, disabled semantics and input refs.hideLabelpreserves the required accessible label. -
CHOICE-05 — Use Pathfinder's existing Check/Minus optical artwork at 12px. Boxes, circles, tracks and thumbs are interactive primitive geometry, styled with the Figma tokens; they are not flattened screenshots. This keeps focus, RTL and switch movement functional.
Explicit differences and boundaries
| Reference | Coverage |
|---|---|
| Editing 442:767 | Account mapping demonstrates select, numeric validation, outline toggle, failed-save recovery and Add line. The companion example composes date, Switch and attachment selection. |