Skip to main content

Switch

A form control that toggles one setting on or off. Unlike Checkbox, it has no indeterminate state.

Pair with Field.* for label/description/error wiring in forms:

Disables wireless radios while in flight.

import { Field } from "@ngrok/mantle/field";import { Switch } from "@ngrok/mantle/switch"; <Field.Item name="airplane-mode-field">	<Field.Label className="inline-flex items-center gap-2">		<Field.Control>			<Switch />		</Field.Control>		Airplane Mode	</Field.Label>	<Field.Description>Disables wireless radios while in flight.</Field.Description></Field.Item>;

Or render the control on its own:

import { Label } from "@ngrok/mantle/label";import { Switch } from "@ngrok/mantle/switch"; <Label htmlFor="airplane-mode" className="flex items-center gap-2">	Airplane Mode	<Switch id="airplane-mode" /></Label>;

Multi-line label with description

For a switch with an emphasized title and a supplementary description beneath it, compose it inside Choice: drop the Switch into Choice.Indicator and pair Choice.Label (a real <label>; clicking it flips the switch, since a <button role="switch"> is a labelable element) with an optional Choice.Description. The switch aligns to the leading of the title's first line, and the description associates via aria-describedby.

Get notified by email when a deploy finishes or a tunnel goes offline.

import { Choice } from "@ngrok/mantle/choice";import { Switch } from "@ngrok/mantle/switch"; <Choice.Root name="email-notifications">	<Choice.Indicator>		<Switch defaultChecked />	</Choice.Indicator>	<Choice.Content>		<Choice.Label>Email notifications</Choice.Label>		<Choice.Description>			Get notified by email when a deploy finishes or a tunnel goes offline.		</Choice.Description>	</Choice.Content></Choice.Root>;

Wrap that same Choice in a Field.Item / Field.Control to bind a form name and pick up validation. The field's id / name / aria-* flow onto the switch, and the Field.Description (or a Field.Errors) is merged into the control's aria-describedby alongside the Choice.Description:

Get notified by email when a deploy finishes or a tunnel goes offline.

You can fine-tune which events notify you later.

import { Choice } from "@ngrok/mantle/choice";import { Field } from "@ngrok/mantle/field";import { Switch } from "@ngrok/mantle/switch"; <Field.Item name="email-notifications">	<Field.Control>		<Choice.Root>			<Choice.Indicator>				<Switch defaultChecked />			</Choice.Indicator>			<Choice.Content>				<Choice.Label>Email notifications</Choice.Label>				<Choice.Description>					Get notified by email when a deploy finishes or a tunnel goes offline.				</Choice.Description>			</Choice.Content>		</Choice.Root>	</Field.Control>	<Field.Description>You can fine-tune which events notify you later.</Field.Description></Field.Item>;

See the Choice docs for the clickable-row variant and the full API.

Examples

Switch in a form with client-side validation

In this example, the Switch is used in a form with client-side validation. The form is built using @tanstack/react-form and zod for validation. The form accepts and validates the input before submission.

import { Button } from "@ngrok/mantle/button";import { Field, toErrorMessages } from "@ngrok/mantle/field";import { Switch } from "@ngrok/mantle/switch";import { useForm } from "@tanstack/react-form";import { z } from "zod"; const formSchema = z.object({	airplaneMode: z.boolean(),});function FormExample() {	const defaultValues = {		airplaneMode: false,	};	const form = useForm({		defaultValues,		validators: {			onSubmit: formSchema,		},		onSubmit: ({ value }) => {			// Handle form submission here		},	}); 	return (		<form			className="space-y-4"			onSubmit={(event) => {				event.preventDefault();				event.stopPropagation();				void form.handleSubmit();			}}		>			<form.Field name="airplaneMode">				{(field) => (					<Field.Item name={field.name}>						<Field.Label className="flex items-center gap-2">							Airplane Mode							<Field.Control>								<Switch									checked={field.state.value}									onBlur={field.handleBlur}									onCheckedChange={(value) => field.handleChange(value)}								/>							</Field.Control>						</Field.Label>						<Field.Errors messages={toErrorMessages(field.state.meta.errors)} />					</Field.Item>				)}			</form.Field>			<Button type="submit" appearance="filled" intent="neutral">				Submit			</Button>		</form>	);}

API Reference

Switch

The Switch is built on top of Radix Switch. It exposes the same API with the following additional props:

PropTypeDefaultDescription
readOnly?booleanfalseMakes the switch immutable, meaning the user can not edit the control. Sets aria-readonly.
validation?"error" | "success" | "warning" | false | () => "error" | "success" | "warning" | falseUse the validation prop to show a specific validation status. This changes the color of the checked track and the focus ring, and stamps data-validation. The false type is useful with short-circuiting logic. Setting validation to "error" also sets aria-invalid.