Switch
An on/off toggle — Attio's settings switch, measured from the live app.
The toggle Attio uses throughout Settings — a 24×16 pill track that flips from a muted grey to brand blue with a 12px white thumb that slides across. Renders a role="switch" button (a native checkbox's semantics without its box), so label association and keyboard (Space / Enter) come for free.
Preview
Enable daily digest
Sent every morning if any tasks are due.
Mentions
Notify me when someone @mentions me.
Disabled
Installation
bun add crispimport "crisp/styles.css";
import { Switch } from "crisp";Usage
Controlled with checked + onCheckedChange, or uncontrolled from defaultChecked:
import { Switch } from "crisp";
import * as React from "react";
function DigestRow() {
const [on, setOn] = React.useState(true);
return (
<label style={{ display: "flex", gap: 12, alignItems: "center" }}>
<span>Enable daily digest</span>
<Switch checked={on} onCheckedChange={setOn} />
</label>
);
}Props
| Prop | Type | Default | Description |
|---|---|---|---|
checked | boolean | — | Controlled on/off. Omit for uncontrolled. |
defaultChecked | boolean | false | Initial value when uncontrolled. |
onCheckedChange | (checked: boolean) => void | — | Fires with the next value on toggle. |
disabled | boolean | false | Dims and blocks interaction. |
aria-label | string | — | Accessible name when there's no associated <label>. |
Any other <button> prop (e.g. id, name) is forwarded.
Notes
- Semantics. It's a
<button role="switch">witharia-checked— screen readers announce "switch, on/off", and Space/Enter toggle it natively. Give it anaria-labelor wrap it in a<label>. - Controlled vs uncontrolled. With
checkedset, the parent owns the value (the switch won't self-update); otherwise it tracks its own state fromdefaultChecked. - Measured. Track
24×16, thumb12px(2px inset, slides8px), on-colour#266df0; the background and thumb both animate.2s.
Used across the settings surface — see it in a settings screen soon.