Switch
A toggle switch component for boolean values. Supports controlled and uncontrolled modes with multiple sizes.
Installation
Terminal
TSXReactTailwind
npx @uiblox/cli add switchVisual Variations
Toggle between three different visual styles: default (rounded), ios (larger), and square (rectangular).
Off
Click to toggle
Enabled
Active toggle
Locked
Non-interactive
Basic Usage
Off
Copy & paste ready
import { Switch } from "@/components/ui";
const [checked, setChecked] = useState(false);
<Switch checked={checked} onCheckedChange={setChecked} />
<span>{checked ? "On" : "Off"}</span>Sizes
Copy & paste ready
<Switch size="sm" defaultChecked />
<Switch size="md" defaultChecked />
<Switch size="lg" defaultChecked />States
Unchecked
Checked
Disabled
Disabled Checked
ReactTailwind CSSCopy & paste ready
<Switch /> {/* Unchecked */}
<Switch defaultChecked /> {/* Checked */}
<Switch disabled /> {/* Disabled */}
<Switch disabled defaultChecked /> {/* Disabled Checked */}With Labels
Dark Mode
Enable dark theme
ReactTailwind CSSCopy & paste ready
<div className="flex items-center justify-between w-64 p-4 border rounded-lg">
<div>
<p className="font-medium">Dark Mode</p>
<p className="text-sm text-gray-500">Enable dark theme</p>
</div>
<Switch />
</div>Props
| Prop | Type | Default | Description |
|---|---|---|---|
| checked | boolean | - | Controlled checked state |
| defaultChecked | boolean | false | Default checked state for uncontrolled usage |
| onCheckedChange | (checked: boolean) => void | - | Callback when checked state changes |
| size | "sm" | "md" | "lg" | "md" | The size of the switch |
| disabled | boolean | false | Whether the switch is disabled |
Source Code
Copy this code into src/components/ui/switch.tsx:
switch.tsx
TSXReactTailwind
"use client";
import * as React from "react";
import { cn } from "@/lib/utils";
interface SwitchProps extends Omit<React.ButtonHTMLAttributes<HTMLButtonElement>, "onChange"> {
checked?: boolean;
defaultChecked?: boolean;
onCheckedChange?: (checked: boolean) => void;
size?: "sm" | "md" | "lg";
}
const Switch = React.forwardRef<HTMLButtonElement, SwitchProps>(
({ className, checked, defaultChecked = false, onCheckedChange, size = "md", disabled, ...props }, ref) => {
const [internalChecked, setInternalChecked] = React.useState(defaultChecked);
const isChecked = checked ?? internalChecked;
const handleClick = () => {
if (disabled) return;
const newChecked = !isChecked;
if (checked === undefined) {
setInternalChecked(newChecked);
}
onCheckedChange?.(newChecked);
};
const sizeClasses = {
sm: "h-4 w-7",
md: "h-5 w-9",
lg: "h-6 w-11",
};
const thumbSizeClasses = {
sm: "h-3 w-3",
md: "h-4 w-4",
lg: "h-5 w-5",
};
const thumbTranslateClasses = {
sm: "translate-x-3",
md: "translate-x-4",
lg: "translate-x-5",
};
return (
<button
ref={ref}
type="button"
role="switch"
aria-checked={isChecked}
disabled={disabled}
onClick={handleClick}
className={cn(
"inline-flex shrink-0 cursor-pointer items-center rounded-full border-2 border-transparent transition-colors",
"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary-500 focus-visible:ring-offset-2",
"disabled:cursor-not-allowed disabled:opacity-50",
isChecked ? "bg-primary-600" : "bg-gray-200 dark:bg-gray-700",
sizeClasses[size],
className
)}
{...props}
>
<span
className={cn(
"pointer-events-none block rounded-full bg-white shadow-lg transition-transform",
thumbSizeClasses[size],
isChecked ? thumbTranslateClasses[size] : "translate-x-0.5"
)}
/>
</button>
);
}
);
Switch.displayName = "Switch";
export { Switch };