apps/eclipse/content/design-system/components/switch.mdx
import { Switch, Field, FieldLabel, FieldDescription } from "@prisma/eclipse"; import { ControlledSwitchExample, SwitchFormExample } from "@/components/switch-examples/interactive-examples";
Basic Switch
import { Switch } from "@prisma/eclipse";
export function BasicSwitch() {
return <Switch />;
}
Live Example:
<div className="flex gap-4 my-4"> <Switch /> </div>With Label
Use labels to make switches more accessible and user-friendly:
import { Switch } from "@prisma/eclipse";
export function SwitchWithLabel() {
return (
<div className="flex items-center gap-2">
<Switch id="airplane-mode" />
<label
htmlFor="airplane-mode"
className="text-sm font-medium leading-none cursor-pointer"
>
Airplane Mode
</label>
</div>
);
}
Live Example:
<div className="flex items-center gap-2 my-4"> <Switch id="airplane-mode-example" /> <label htmlFor="airplane-mode-example" className="text-sm font-medium leading-none cursor-pointer" > Airplane Mode </label> </div>With Field Component
Use the Field component for proper form structure with labels and descriptions:
import { Switch, Field, FieldLabel, FieldDescription } from "@prisma/eclipse";
export function SwitchWithField() {
return (
<Field orientation="horizontal" className="justify-between">
<div className="flex flex-col gap-1">
<FieldLabel htmlFor="notifications">Push Notifications</FieldLabel>
<FieldDescription>Receive push notifications on your device.</FieldDescription>
</div>
<Switch id="notifications" />
</Field>
);
}
Live Example:
<div className="max-w-md my-4"> <Field orientation="horizontal" className="justify-between"> <div className="flex flex-col gap-1"> <FieldLabel htmlFor="notifications-field">Push Notifications</FieldLabel> <FieldDescription>Receive push notifications on your device.</FieldDescription> </div> <Switch id="notifications-field" /> </Field> </div>Controlled Switch
Control the switch state with React state:
import { Switch } from "@prisma/eclipse";
import { useState } from "react";
export function ControlledSwitch() {
const [enabled, setEnabled] = useState(false);
return (
<div className="space-y-4">
<div className="flex items-center gap-2">
<Switch
id="controlled"
checked={enabled}
onCheckedChange={setEnabled}
/>
<label htmlFor="controlled" className="text-sm font-medium">
Feature enabled
</label>
</div>
<p className="text-sm text-foreground-neutral-weak">
Status: {enabled ? "On" : "Off"}
</p>
</div>
);
}
Live Example:
<div className="my-4"> <ControlledSwitchExample /> </div>Disabled State
import { Switch } from "@prisma/eclipse";
export function DisabledSwitch() {
return (
<div className="space-y-4">
<div className="flex items-center gap-2">
<Switch id="disabled-off" disabled />
<label
htmlFor="disabled-off"
className="text-sm font-medium opacity-70 cursor-not-allowed"
>
Disabled (off)
</label>
</div>
<div className="flex items-center gap-2">
<Switch id="disabled-on" disabled checked />
<label
htmlFor="disabled-on"
className="text-sm font-medium opacity-70 cursor-not-allowed"
>
Disabled (on)
</label>
</div>
</div>
);
}
Live Example:
<div className="space-y-4 my-4"> <div className="flex items-center gap-2"> <Switch id="disabled-off-example" disabled /> <label htmlFor="disabled-off-example" className="text-sm font-medium opacity-70 cursor-not-allowed" > Disabled (off) </label> </div> <div className="flex items-center gap-2"> <Switch id="disabled-on-example" disabled checked /> <label htmlFor="disabled-on-example" className="text-sm font-medium opacity-70 cursor-not-allowed" > Disabled (on) </label> </div> </div>Settings Panel Example
Create a settings panel with multiple switches:
import { Switch, Field, FieldLabel, FieldDescription } from "@prisma/eclipse";
export function SettingsPanel() {
return (
<div className="space-y-6 max-w-md">
<h3 className="text-lg font-semibold">Notification Settings</h3>
<Field orientation="horizontal" className="justify-between">
<div className="flex flex-col gap-1">
<FieldLabel htmlFor="email-notifications">Email Notifications</FieldLabel>
<FieldDescription>Receive notifications via email.</FieldDescription>
</div>
<Switch id="email-notifications" defaultChecked />
</Field>
<Field orientation="horizontal" className="justify-between">
<div className="flex flex-col gap-1">
<FieldLabel htmlFor="push-notifications">Push Notifications</FieldLabel>
<FieldDescription>Receive push notifications on your devices.</FieldDescription>
</div>
<Switch id="push-notifications" />
</Field>
<Field orientation="horizontal" className="justify-between">
<div className="flex flex-col gap-1">
<FieldLabel htmlFor="sms-notifications">SMS Notifications</FieldLabel>
<FieldDescription>Receive notifications via text message.</FieldDescription>
</div>
<Switch id="sms-notifications" />
</Field>
</div>
);
}
Live Example:
<div className="space-y-6 max-w-md my-4"> <h3 className="text-lg font-semibold">Notification Settings</h3> <Field orientation="horizontal" className="justify-between"> <div className="flex flex-col gap-1"> <FieldLabel htmlFor="email-notifications-example">Email Notifications</FieldLabel> <FieldDescription>Receive notifications via email.</FieldDescription> </div> <Switch id="email-notifications-example" defaultChecked /> </Field> <Field orientation="horizontal" className="justify-between"> <div className="flex flex-col gap-1"> <FieldLabel htmlFor="push-notifications-example">Push Notifications</FieldLabel> <FieldDescription>Receive push notifications on your devices.</FieldDescription> </div> <Switch id="push-notifications-example" /> </Field> <Field orientation="horizontal" className="justify-between"> <div className="flex flex-col gap-1"> <FieldLabel htmlFor="sms-notifications-example">SMS Notifications</FieldLabel> <FieldDescription>Receive notifications via text message.</FieldDescription> </div> <Switch id="sms-notifications-example" /> </Field> </div>Form Integration
import { Switch } from "@prisma/eclipse";
import { useState } from "react";
export function SwitchForm() {
const [settings, setSettings] = useState({
darkMode: false,
notifications: true,
analytics: false,
});
const handleSubmit = (e: React.FormEvent) => {
e.preventDefault();
console.log("Settings:", settings);
};
return (
<form onSubmit={handleSubmit} className="space-y-6 max-w-md">
<h3 className="text-lg font-semibold">App Settings</h3>
<div className="flex items-center justify-between">
<label htmlFor="dark-mode" className="text-sm font-medium">
Dark Mode
</label>
<Switch
id="dark-mode"
checked={settings.darkMode}
onCheckedChange={(checked) =>
setSettings({ ...settings, darkMode: checked })
}
/>
</div>
<div className="flex items-center justify-between">
<label htmlFor="notifications-form" className="text-sm font-medium">
Enable Notifications
</label>
<Switch
id="notifications-form"
checked={settings.notifications}
onCheckedChange={(checked) =>
setSettings({ ...settings, notifications: checked })
}
/>
</div>
<div className="flex items-center justify-between">
<label htmlFor="analytics-form" className="text-sm font-medium">
Analytics
</label>
<Switch
id="analytics-form"
checked={settings.analytics}
onCheckedChange={(checked) =>
setSettings({ ...settings, analytics: checked })
}
/>
</div>
<button
type="submit"
className="px-4 py-2 bg-primary text-primary-foreground rounded-md"
>
Save Settings
</button>
</form>
);
}
Live Example:
<div className="my-4"> <SwitchFormExample /> </div>Switch
The Switch component extends all Radix UI Switch props:
checked - Controlled checked state (boolean, optional)defaultChecked - Default checked state for uncontrolled usage (boolean, optional)onCheckedChange - Callback when checked state changes ((checked: boolean) => void, optional)disabled - Whether the switch is disabled (boolean, default: false)required - Whether the switch is required (boolean, default: false)name - Name for form submission (string, optional)value - Value for form submission (string, default: "on")id - HTML id attribute (string, optional)className - Additional CSS classes (string, optional)htmlFor on labels to match switch id for clickable labelsThe Switch component is perfect for:
Use Switch when:
Use Checkbox when:
The Switch component follows accessibility best practices:
role="switch", aria-checked)prefers-reduced-motionThe Switch component uses Eclipse design tokens:
bg-inputbg-primarybg-background (unchecked), bg-primary-foreground (checked in dark mode)ring-ring/50 with 3px widthrounded-full)shadow-xsCustomize by passing className:
<Switch className="data-[state=checked]:bg-green-500" />
Switch works well with:
The Switch component works seamlessly with forms:
<form onSubmit={handleSubmit}>
<Switch name="notifications" value="enabled" defaultChecked />
<button type="submit">Submit</button>
</form>
When checked, the form data will include: notifications=enabled
The Switch component includes smooth animations:
The Switch component automatically adapts to dark mode:
bg-input/80 in dark modebg-foreground when unchecked in dark mode