Switch

@sushindustries/ui

A checkbox that admits it: a real input with role=switch, and a track :checked drives.

4 min read
View as MarkdownEdit on GitHub

Examples are the tab where the component is shown doing a job, not demonstrating a prop. The API tab already lists the props.

Viewport width
Phone22remthe floor, the narrowest this promises to work at
tanstacktanstack add https://adamjurek.com/r/tanstack/switch.jsonshadcnpnpm dlx shadcn@latest add https://adamjurek.com/r/shadcn/switch.json

Press Compare. The frames are real viewports, so a layout that breaks at 320 breaks here too rather than in somebody's hands.

In a page

import { useState } from "react";
import { Switch } from "@sushindustries/ui";

export function ScrollPreferences() {
	const [smooth, setSmooth] = useState(true);
	const [reducedMotion, setReducedMotion] = useState(false);

	return (
		<fieldset className="flex flex-col gap-3">
			<legend className="label">Motion</legend>
			<Switch
				label="Smooth scrolling"
				checked={smooth}
				onChange={(event) => setSmooth(event.target.checked)}
			/>
			<Switch
				label="Reduce motion"
				checked={reducedMotion}
				onChange={(event) => setReducedMotion(event.target.checked)}
			/>
		</fieldset>
	);
}
tsx

What this example is not

Each switch here changes its own setting immediately - neither is wired to a submit button. That immediacy is what role="switch" promises; a form that needs a confirm step before anything takes effect should use CheckboxCheckboxA native checkbox with its words attached, painted by accent-color rather than redrawn.@sushindustries/ui · content instead, not a SwitchSwitchA checkbox that admits it: a real input with role=switch, and a track :checked drives.@sushindustries/ui · content gated behind a button.