Installation
npm install @kuzenbo/core @kuzenbo/theme
Usage
import { Switch } from "@kuzenbo/core";
import { Label } from "@kuzenbo/core";
function App() {
return (
<Label className="flex items-center gap-2">
<Switch aria-label="Toggle feature" />
Enable feature
</Label>
);
}
Examples
Controlled Switch
Manage switch state with React.
import { Switch } from "@kuzenbo/core";
import { Label } from "@kuzenbo/core";
import { useState } from "react";
function ControlledExample() {
const [enforceSso, setEnforceSso] = useState(false);
return (
<div className="grid gap-2">
<Label className="flex items-center gap-2" htmlFor="enforce-sso">
<Switch
checked={enforceSso}
id="enforce-sso"
onCheckedChange={setEnforceSso}
/>
Enforce SSO for all collaborators
</Label>
<p className="text-muted-foreground text-sm">
{enforceSso
? "Password login is disabled for this workspace."
: "Members can still sign in with local credentials."}
</p>
</div>
);
}
Default Checked
Set initial state using defaultChecked.
import { Switch } from "@kuzenbo/core";
import { Label } from "@kuzenbo/core";
function DefaultCheckedExample() {
return (
<Label className="flex items-center gap-2">
<Switch defaultChecked aria-label="Alert routing" />
Route high-priority alerts to on-call channel
</Label>
);
}
Sizes
Switches are available in five size variants.
import { Switch } from "@kuzenbo/core";
import { Label } from "@kuzenbo/core";
function SizesExample() {
return (
<div className="grid gap-2">
<div className="flex items-center gap-2">
<Switch size="xs" defaultChecked />
<Label>XS density</Label>
</div>
<div className="flex items-center gap-2">
<Switch size="sm" defaultChecked />
<Label>SM density</Label>
</div>
<div className="flex items-center gap-2">
<Switch size="md" defaultChecked />
<Label>MD density</Label>
</div>
<div className="flex items-center gap-2">
<Switch size="lg" defaultChecked />
<Label>LG density</Label>
</div>
<div className="flex items-center gap-2">
<Switch size="xl" defaultChecked />
<Label>XL density</Label>
</div>
</div>
);
}
Disabled
Disabled switches are non-interactive and visually muted.
import { Switch } from "@kuzenbo/core";
import { Label } from "@kuzenbo/core";
function DisabledExample() {
return (
<Label className="flex items-center gap-2">
<Switch disabled aria-label="Locked setting" />
Allow external API tokens
</Label>
);
}
Custom Thumb
Customize the switch thumb appearance.
import { Switch } from "@kuzenbo/core";
import { Label } from "@kuzenbo/core";
function CustomThumbExample() {
return (
<Label className="flex items-center gap-2">
<Switch defaultChecked>
<Switch.Thumb>
<span className="sr-only">Custom thumb</span>
</Switch.Thumb>
</Switch>
Gradual feature rollout
</Label>
);
}
Props
Switch extends Base UI Switch.Root props.
Size variant of the switch.Options: "xs" | "sm" | "md" | "lg" | "xl"
Controlled checked state of the switch.
Default checked state for uncontrolled usage.
onCheckedChange
(checked: boolean) => void
Callback fired when the checked state changes.
When true, disables the switch and makes it non-interactive.
Accessible label for the switch. Required when not using a visible label.
Additional CSS classes to apply to the switch.
Custom thumb content. Defaults to the standard thumb.
Subcomponents
Switch.Thumb
The movable thumb element that slides when the switch is toggled.
<Switch>
<Switch.Thumb />
</Switch>
TypeScript
import type { SwitchProps, SwitchThumbProps } from "@kuzenbo/core";
const CustomSwitch = (props: SwitchProps) => {
return <Switch {...props} />;
};
Accessibility
- Switch uses semantic ARIA switch role
- Supports keyboard navigation with Space and Enter to toggle
- Properly announces on/off state to screen readers
- Visual focus indicators for keyboard navigation
- Disabled state prevents all interactions
- Always provide an accessible label via
aria-label or associated Label component