Theme Switcher

Switch

A control that allows the user to toggle between checked and not checked.

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>

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-formand zod for validation. The form accepts and validates the input before submission.

import { Button } from "@ngrok/mantle/button";
import { Label } from "@ngrok/mantle/label";
import { Switch } from "@ngrok/mantle/switch";
import { useForm } from "@tanstack/react-form";
import { z } from "zod";
import { useSubmit } from "react-router";

const formSchema = z.object({
	airplaneMode: z.boolean(),
});

type FormValues = z.infer<typeof formSchema>;

function FormExample() {
	const submit = useSubmit();
	const form = useForm({
		defaultValues: {
			airplaneMode: false,
		} satisfies FormValues as FormValues,
		validators: {
			onSubmit: formSchema,
		},
		onSubmit: ({ value }) => {
			// Handle form submission here
			submit(value, {
				method: "post",
			});
		},
	});

	return (
		<form
			className="space-y-4"
			onSubmit={(event) => {
				event.preventDefault();
				event.stopPropagation();
				void form.handleSubmit();
			}}
		>
			<div className="space-y-1">
				<form.Field name="airplaneMode">
					{(field) => (
						<Label htmlFor={field.name} className="flex items-center gap-2">
							Airplane Mode
							<Switch
								name={field.name}
								id={field.name}
								checked={field.state.value}
								onBlur={field.handleBlur}
								onCheckedChange={(value) => field.handleChange(value)}
							/>
						</Label>
					)}
				</form.Field>
				<form.Field name="airplaneMode">
					{(field) =>
						field.state.meta.errors.map((error) => (
							<p
								key={error?.message}
								className="text-sm leading-4 text-danger-600"
							>
								{error?.message}
							</p>
						))
					}
				</form.Field>
			</div>
			<form.Subscribe selector={(state) => state.isDirty}>
				{(isDirty) => (
					<Button type="submit" appearance="filled" disabled={!isDirty}>
						Submit
					</Button>
				)}
			</form.Subscribe>
		</form>
	);
}

API Reference

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

PropTypeDefaultDescription
readOnly
booleanfalse

Makes the switch immutable, meaning the user can not edit the control.