Switch
StableAn on/off switch for settings that apply at once: label and hint on the left, a sunken track with a pearl thumb on the right.
A <button role="switch"> that flips the moment it is pressed, with no Save step. On, the track fills solid and the thumb slides right; off, the track is pale and the thumb sits left. Clicking the label text flips it too.
Notification settings
import { useState } from 'react'import { Switch } from '@rchursin/product/ui'
/** * For settings that apply the moment they change, with no Save button. The label and hint sit * on the left; clicking the label flips the switch too. */export default function SwitchSettings() { const [due, setDue] = useState(true) const [weekly, setWeekly] = useState(false)
return ( <div className="flex w-full max-w-sm flex-col divide-y divide-line"> <Switch className="pb-4" label="Email me when a task is due" hint="Sent at 9:00 in your time zone." checked={due} onChange={setDue} /> <Switch className="py-4" label="Weekly summary" hint="Mondays: what you finished and what slipped." checked={weekly} onChange={setWeekly} /> <Switch className="pt-4" label="Desktop notifications" hint="Blocked in this browser’s site settings." checked={false} onChange={() => {}} disabled /> </div> )}Usage
import { Switch } from '@rchursin/product/ui'<Switch label="Weekly summary" hint="Mondays at 9:00." checked={weekly} onChange={setWeekly} />Examples
Applies at once
Flip it and the list below changes straight away: that is when a switch is the right control.
import { useState } from 'react'import { cx } from '@rchursin/components/cx'import { Switch } from '@rchursin/product/ui'
const tasks = ['Review the cost report', 'Rename the pr-review skill', 'Draft release notes']
/** The switch's effect shows straight away: the list below tightens or loosens as you flip it. */export default function SwitchApplyNow() { const [compact, setCompact] = useState(false)
return ( <div className="flex w-full max-w-sm flex-col gap-4"> <Switch label="Compact rows" hint="Fit more tasks on the screen." checked={compact} onChange={setCompact} /> <ul aria-label="Sample tasks" className="lux-card-flat flex flex-col divide-y divide-line rounded-xl bg-raised"> {tasks.map((t) => ( <li key={t} className={cx('px-3 text-[13px] text-fg motion-safe:transition-[padding] motion-safe:duration-200', compact ? 'py-1.5' : 'py-3')}> {t} </li> ))} </ul> </div> )}API
Switch props
| Prop | Type | Default | Description |
|---|---|---|---|
checkedrequired | boolean | – | On or off. |
onChangerequired | (v: boolean) => void | – | Called with the new state when the switch or its label is pressed. |
labelrequired | ReactNode | – | What the switch turns on. It is the switch’s name (aria-labelledby). |
hint | ReactNode | – | A line under the label, linked with aria-describedby. |
disabled | boolean | – | Fades the switch to 45% and takes it out of the tab order. Say why in the hint. |
className | string | – | Classes on the row (label column and switch). |
CSS
| Class or variable | What it does |
|---|---|
rc-switch | On a <button role="switch"> with an empty <span> inside: a 36 × 20px track and a 16px thumb. aria-checked="true" fills the track and slides the thumb 16px right. |
Accessibility
Keyboard
| Key | What it does |
|---|---|
| SpaceEnter | Flips the switch. Focus stays on it. |
| Tab | Moves to the next switch. Each one is its own Tab stop. |
- A real <button> with role="switch" and aria-checked, so screen readers say “Weekly summary, switch, off”.
- The label text is the name (aria-labelledby) and the hint is the description (aria-describedby).
- Clicking the label flips the switch but does not move focus; keyboard users reach the switch itself.
- It is a button, not a form input: it sends nothing with a <form>. Save the value from onChange.
Guidelines
Do
- Use it for settings that take effect immediately.
- Name what is on, not the action: “Weekly summary”, not “Turn on weekly summary”.
- Show the effect, or confirm it, right away.
Don’t
- Don’t use a switch in a form that waits for a Submit button: use Checkbox.
- Don’t change the label text with the state; the switch already shows it.
In use
Related
- CheckboxA labelled checkbox drawn as the brand square with a cut-in tick, with a hint and a mixed state.
- Segmented controlA radio group drawn as one strip, with a lit pill that glides to the choice and arrow keys that move and choose.
- Dark modeOne class flips every token: on <html> for the whole page, or on any wrapper for one part of it.
Source
The component’s own files, exactly as they run on this site.
/** * Form fields. Labels sit above inputs, hints under the label, errors between the hint and the * input with an icon and the word "Error:" for screen readers (never colour alone). * Optional fields say "(optional)"; required ones carry no mark. * * <Field label="Email" hint="We send the sign-in code here." error={err}> * {(p) => <TextInput {...p} type="email" autoComplete="email" />} * </Field> */import { forwardRef, useId, useLayoutEffect, useRef, useState, type InputHTMLAttributes, type KeyboardEvent, type ReactNode, type SelectHTMLAttributes, type TextareaHTMLAttributes,