Docs
Switch
Switch
A Switch component that allows a user to toggle between checked and not checked.
Installation
Copy and paste the following code into your component.
import * as React from "react";
import styles from "./switch.module.css";
export interface SwitchProps
extends React.InputHTMLAttributes<HTMLInputElement> {
onCheckedChange: (checked: boolean) => void;
checked?: boolean | undefined;
id?: string;
}
const SWITCH_NAME = "Switch";
const Switch = React.forwardRef<HTMLInputElement, SwitchProps>(
({ className, onCheckedChange, checked = false, id, ...props }, ref) => {
const [isFocused, setIsFocused] = React.useState(false);
// We only want to handle the enter key when the Switch is focused,
// this prevents bubbling issues when Switch is a form field
const handleFocus = () => {
setIsFocused(true);
};
const handleBlur = () => {
setIsFocused(false);
};
const handleButtonClick = () => {
onCheckedChange(!checked);
};
const handleKeyDown = (event: React.KeyboardEvent<HTMLButtonElement>) => {
if (event.key === "Enter") {
event.preventDefault();
handleButtonClick();
}
};
return (
<span className={styles.switchContainer}>
<button
role='switch'
onFocus={handleFocus}
onBlur={handleBlur}
onClick={isFocused ? handleButtonClick : undefined}
onKeyDown={handleKeyDown}
aria-checked={checked}
aria-required={props.required}
data-state={checked}
data-disabled={props.disabled ? "" : undefined}
disabled={props.disabled}
tabIndex={0}
className={styles.switchTrack}>
<div className={styles.switchThumb} />
</button>
<input
type='checkbox'
className={styles.switchInput}
checked={checked}
onChange={(e) => onCheckedChange(e.target.checked)}
ref={ref}
aria-hidden
tabIndex={-1}
id={id}
{...props}
/>
</span>
);
}
);
Switch.displayName = SWITCH_NAME;
export { Switch };
Copy and paste the following CSS into a .module.css file.
.switchContainer {
border: 2px solid transparent;
cursor: pointer;
display: inline-block;
height: 1.5rem;
position: relative;
width: 2.75rem;
}
.switchTrack {
background-color: hsl(var(--input));
border-radius: 12px;
bottom: 0;
left: 0;
outline-offset: 2px;
position: absolute;
right: 0;
top: 0;
transition: background-color 0.3s ease;
}
.switchTrack:disabled {
opacity: 0.5;
}
.switchTrack[aria-checked="true"] {
background-color: hsl(var(--primary));
}
.switchTrack[aria-checked="true"] .switchThumb {
transform: translateX(1.125rem);
}
.switchTrack:focus {
outline: 2px solid hsl(var(--secondary));
}
.switchThumb {
background: hsl(var(--background));
border-radius: 50%;
height: 1.125rem;
top: 1px;
left: 2px;
position: absolute;
transition: transform 0.3s ease;
width: 1.125rem;
}
.switchInput {
cursor: pointer;
height: 100%;
opacity: 0;
position: absolute;
width: 100%;
}
Update the import paths to match your project setup.
Usage
import { Switch } from "@/components/ui/switch";
<Switch id='optOut' checked={true} onCheckedChange={() => {}} />