Switch
A 34×20 on/off toggle for settings that take effect as soon as they change. It is a <button role="switch">, not a checkbox.
<Switch defaultChecked>Dark mode</Switch>Import
import { Switch } from "@merid/react";Examples
Controlled
defaultChecked keeps state inside the switch. For controlled use pass checked and onCheckedChange, which receives the next boolean.
const [on, setOn] = useState(false);
<Switch checked={on} onCheckedChange={setOn}>
Auto-save drafts
</Switch>Label position
<Switch labelPosition="start">Label at start</Switch>
<Switch labelPosition="end">Label at end</Switch>Disabled and unlabelled
Without children, give the switch an aria-label.
<Switch disabled>Disabled off</Switch>
<Switch disabled defaultChecked>Disabled on</Switch>
<Switch aria-label="Notifications" />In a form
A button does not submit a value on its own. Set name and the switch renders a hidden input that submits value (default "on") while it is on — nothing is submitted while off.
<form>
<Switch name="newsletter" value="yes" defaultChecked>
Subscribe to newsletter
</Switch>
</form>API reference
The ref and remaining button attributes go to the track <button>; className goes to the outer wrapper.
| Prop | Type | Default | Description |
|---|---|---|---|
checked | boolean | – | On state (controlled). |
defaultChecked | boolean | false | Initial on state (uncontrolled). |
onCheckedChange | (checked: boolean) => void | – | Called with the new state when toggled. |
children | ReactNode | – | Visible label; becomes the accessible name. Otherwise pass aria-label. |
labelPosition | "start" | "end" | "end" | Which side the label sits on. |
name | string | – | When set, a hidden input with this name submits value while on. |
value | string | "on" | Submitted value when on. |
disabled | boolean | – | Disables the switch and dims the label. Inside a `Field`, inherited from it. |
invalid | boolean | – | Forces the invalid style (`data-invalid`) and `aria-invalid`. Inside a `Field`, derived from its `error`. |
Styling
| Hook | Values |
|---|---|
.mrd-switch | Wrapper; receives className |
.mrd-switch__track | The <button role="switch"> |
.mrd-switch__thumb | Moving thumb |
.mrd-switch__label | Visible label |
data-state | on · off (wrapper and track) |
data-label-position | start · end |
data-disabled | On the wrapper when disabled |
data-invalid | On the track when invalid; draws the danger ring |
Switch has no component variables; the off track uses --mrd-control-off and the on track --mrd-accent.
Accessibility
- Exposed as
role="switch"witharia-checked, so screen readers announce “on” / “off”. - The visible label is linked with
aria-labelledby; clicking it also toggles the switch. - Inside a
Field, the switch takes the Field id (so the Field label names it), plus itsaria-describedby,aria-invalidanddisabled. aria-invalidcarries the invalid semantics;data-invaliddrives the styling.
| Key | Action |
|---|---|
| Tab | Moves focus to the switch. |
| Space | Toggles the switch. |
| Enter | Toggles the switch. |
Guidelines
Do
Use a switch for settings that apply instantly, and label it with the setting name: “Dark mode”.
Avoid
Use a switch in a form that needs a Save button — use a Checkbox.
Do
Keep the label static; the switch itself shows the state.
Avoid
Change the label between “On” and “Off” — it duplicates the state and confuses screen reader users.
Related
- Checkbox — choices applied on submit.
- SegmentedControl — pick between named modes.