Switch
A toggle switch input with an optional label. Uses the native switch ARIA role for binary on/off states, with no indeterminate state. Supports controlled and uncontrolled modes.
import { Switch } from "@tenstorrent/vesper/switch";
export default function SwitchDemo() {
return <Switch label="Enable notifications" />;
}Options
| Prop | Type | Description | Default |
|---|---|---|---|
label | string | The text label displayed next to the switch. An asterisk is appended when required is true. | — |
size | "sm" | "md" | The size of the switch and its label. | "md" |
ref | Ref<HTMLInputElement> | A ref forwarded to the underlying <input> element. | — |
checked | boolean | Controls the checked state (controlled mode). | — |
defaultChecked | boolean | The initial checked state (uncontrolled mode). | false |
disabled | boolean | When true, prevents interaction. | false |
required | boolean | When true, marks the input as required and appends an asterisk to the label. | false |
onChange | ChangeEventHandler<HTMLInputElement> | Callback fired when the switch is toggled. | — |
Form and accessibility props such as autoFocus, tabIndex, aria-label, aria-labelledby, aria-describedby, aria-invalid, and event handlers like onFocus, onBlur, and onKeyDown are forwarded to the underlying <input> element, as is ref. Any other props, including className, are forwarded to the wrapping <label> element.
Use the Switch component when toggling a setting on and off takes effect immediately. Reach for the Checkbox component instead when building form fields, such as accepting terms or opting into a mailing list, or when you need to represent an indeterminate state.
Examples
Controlled vs uncontrolled
Render a Switch in an uncontrolled fashion to let it keep track of its own checked state. Pass defaultChecked if it should start out checked:
import { Switch } from "@tenstorrent/vesper/switch";
export default function UncontrolledSwitch() {
return <Switch label="Allow notifications" defaultChecked />;
}If you need to control whether the switch is checked, you can do so via the checked and onChange props. The new state is read from the event's target.checked:
Checked: false
import { useState } from "react";
import { Button } from "@tenstorrent/vesper/button";
import { Switch } from "@tenstorrent/vesper/switch";
import { Typography } from "@tenstorrent/vesper/typography";
export default function ControlledSwitch() {
const [notificationsEnabled, setNotificationsEnabled] = useState(false);
return (
<div
style={{
display: "flex",
flexDirection: "column",
gap: "var(--vesper-spacing-4)",
}}
>
<Switch
label="Allow notifications"
checked={notificationsEnabled}
onChange={(e) => setNotificationsEnabled(e.target.checked)}
/>
<Typography variant="copy-sm">
Checked: {String(notificationsEnabled)}
</Typography>
<Button size="sm" onClick={() => setNotificationsEnabled(false)}>
Reset
</Button>
</div>
);
}Different sizes
The Switch component can be rendered at sm or md size, defaulting to md. Size affects the dimensions of the switch itself, as well as the text styles of the text rendered beside it.
import { Switch } from "@tenstorrent/vesper/switch";
export default function SwitchSizes() {
return (
<div
style={{
display: "flex",
flexDirection: "column",
gap: "var(--vesper-spacing-4)",
}}
>
<Switch size="sm" label="A small switch" />
<Switch size="md" label="A medium switch" />
</div>
);
}Disabling the switch
You can disable a Switch by passing disabled={true} or just disabled as a prop. A disabled switch still displays its current state, but it cannot be toggled by pointer or keyboard, is skipped in the tab order, and is excluded from form data:
import { Switch } from "@tenstorrent/vesper/switch";
export default function DisabledSwitches() {
return (
<div
style={{
display: "flex",
flexDirection: "column",
gap: "var(--vesper-spacing-4)",
}}
>
<Switch label="Sign up for our newsletter" disabled />
<Switch label="Sign up for our newsletter" defaultChecked disabled />
</div>
);
}Usage in forms
Switch renders a native <input type="checkbox">, so it works with regular form submission and native validation via props like name, value, form, and required. A switch that is turned on submits its value (defaulting to "on"), and a turned-off switch is omitted from form data entirely.
Pass required when the switch must be turned on before the form can be submitted:
import { useState } from "react";
import { Button } from "@tenstorrent/vesper/button";
import { Switch } from "@tenstorrent/vesper/switch";
import { Typography } from "@tenstorrent/vesper/typography";
export default function FormSwitchDemo() {
const [submitted, setSubmitted] = useState<string | null>(null);
return (
<form
style={{
display: "flex",
flexDirection: "column",
gap: "var(--vesper-spacing-4)",
}}
onSubmit={(event) => {
event.preventDefault();
const data = new FormData(event.currentTarget);
setSubmitted(String(data.get("notifications") ?? ""));
}}
>
<Switch
required
name="notifications"
value="enabled"
label="Enable notifications"
/>
<Button size="sm" type="submit">
Submit
</Button>
{submitted !== null && (
<Typography variant="copy-sm">
Submitted value: notifications={submitted}
</Typography>
)}
</form>
);
}The form above submits notifications=enabled once the switch is turned on, and refuses to submit at all while it is turned off.
Use the form prop to associate the field with a <form> rendered elsewhere on the page:
import { Button } from "@tenstorrent/vesper/button";
import { Switch } from "@tenstorrent/vesper/switch";
export default function SwitchFormPropDemo() {
return (
<div>
<form id="settings" action="/api/settings" method="post">
<Button type="submit">Save settings</Button>
</form>
{/* rendered outside of the form, but submitted with it */}
<Switch
required
form="settings"
name="notifications"
value="enabled"
label="Enable notifications"
/>
</div>
);
}Accessing the underlying element
Use the ref prop when you need direct access to the underlying <input> element, eg. to focus it or report a custom validation message:
import { useRef } from "react";
import { Switch } from "@tenstorrent/vesper/switch";
export default function SwitchRefDemo() {
const ref = useRef<HTMLInputElement>(null);
return (
<Switch
required
ref={ref}
label="Enable telemetry"
onChange={() => ref.current?.setCustomValidity("")}
onInvalid={() =>
ref.current?.setCustomValidity(
"Telemetry must be enabled when opting into nightly builds",
)
}
/>
);
}