Why Use It
- Best for binary settings such as notifications, assistive features, and device preferences.
- Uses the Radix switch state model, so controlled and uncontrolled usage both stay straightforward.
- Keeps the original glossy shell, thumb, and inline ON or OFF labels without extra styling work.
- Fits well inside form fields and settings rows because the component is already compact and self-contained.
Installation
Install the switch directly, then pair it with labels or helper text in your own settings layout.
$ bunx --bun shadcn@latest add https://sabraman.ru/r/legacy-switch.jsonQuick Start
Start with a single controlled switch and a plain text status label.
"use client";
import { useState } from "react";
import { LegacySwitch } from "@/components/legacy-switch";
export function LegacySwitchUsageExample() {
const [enabled, setEnabled] = useState(true);
return (
<div className="flex items-center gap-4">
<LegacySwitch
aria-label="Notifications"
checked={enabled}
onCheckedChange={setEnabled}
/>
<span className="font-medium text-sm">
{enabled ? "Notifications enabled" : "Notifications disabled"}
</span>
</div>
);
}Examples
Controlled Toggle
A basic controlled toggle for the default notifications-style pattern.
"use client";
import { useState } from "react";
import { LegacySwitch } from "@/components/legacy-switch";
export function LegacySwitchUsageExample() {
const [enabled, setEnabled] = useState(true);
return (
<div className="flex items-center gap-4">
<LegacySwitch
aria-label="Notifications"
checked={enabled}
onCheckedChange={setEnabled}
/>
<span className="font-medium text-sm">
{enabled ? "Notifications enabled" : "Notifications disabled"}
</span>
</div>
);
}Settings Row
Pair the switch with a title and helper copy inside a settings row.
Wi-Fi Assist
Use mobile data when the current network stops responding.
"use client";
import { useState } from "react";
import { LegacySwitch } from "@/components/legacy-switch";
export function LegacySwitchSettingsRowExample() {
const [wifiAssist, setWifiAssist] = useState(true);
return (
<div className="w-full max-w-[340px] rounded-[18px] border border-white/10 bg-[linear-gradient(180deg,#f7f8fa_0%,#e3e8ef_100%)] p-4 shadow-[0_10px_24px_rgba(0,0,0,0.18),inset_0_1px_0_rgba(255,255,255,0.92)]">
<div className="flex items-center justify-between gap-4 rounded-[14px] border border-[#ccd3df] bg-white/80 px-4 py-3 shadow-[inset_0_1px_0_rgba(255,255,255,0.92)]">
<div className="min-w-0">
<p className="font-semibold text-[#556178] text-sm">Wi-Fi Assist</p>
<p className="mt-1 text-[#72809a] text-sm leading-relaxed">
Use mobile data when the current network stops responding.
</p>
</div>
<LegacySwitch
aria-label="Wi-Fi Assist"
checked={wifiAssist}
onCheckedChange={setWifiAssist}
/>
</div>
</div>
);
}Disabled States
Render disabled on and off states when a setting is locked or unavailable.
"use client";
import { LegacySwitch } from "@/components/legacy-switch";
export function LegacySwitchDisabledExample() {
return (
<div className="flex flex-wrap items-center gap-6">
<div className="flex items-center gap-3">
<LegacySwitch aria-label="Airplane mode off" disabled={true} />
<span className="font-medium text-sm text-white/80">Off</span>
</div>
<div className="flex items-center gap-3">
<LegacySwitch
aria-label="Airplane mode on"
checked={true}
disabled={true}
/>
<span className="font-medium text-sm text-white/80">On</span>
</div>
</div>
);
}Form-Controlled Switch
Use the switch inside form state when the toggle is part of a larger preferences form.
"use client";
import type { SubmitHandler } from "react-hook-form";
import { useForm } from "react-hook-form";
import { LegacyBarButton } from "@/components/legacy-bar-button";
import { showLegacyNotification } from "@/components/legacy-notification";
import { LegacySwitch } from "@/components/legacy-switch";
import {
Form,
FormControl,
FormField,
FormItem,
FormLabel,
} from "@/components/ui/form";
type SwitchFormValues = {
notifications: boolean;
};
export function LegacySwitchFormExample() {
const form = useForm<SwitchFormValues>({
defaultValues: {
notifications: true,
},
});
const onSubmit: SubmitHandler<SwitchFormValues> = (values) => {
showLegacyNotification({
body: values.notifications
? "Push notifications are enabled."
: "Push notifications are disabled.",
showIcon: false,
subtitle: "Notifications",
time: "now",
title: "Preferences Updated",
});
};
return (
<Form {...form}>
<form
className="flex w-full max-w-[340px] flex-col gap-5"
onSubmit={form.handleSubmit(onSubmit)}
>
<FormField
control={form.control}
name="notifications"
render={({ field }) => (
<FormItem className="flex items-center justify-between gap-4 rounded-[14px] border border-white/10 bg-white/6 px-4 py-3">
<div>
<FormLabel className="font-medium text-sm text-white">
Push Notifications
</FormLabel>
<p className="mt-1 text-[#8b9bb4] text-sm leading-relaxed">
Use a controlled switch inside form state without losing the
legacy chrome.
</p>
</div>
<FormControl>
<LegacySwitch
aria-label="Push notifications"
checked={field.value}
onCheckedChange={field.onChange}
/>
</FormControl>
</FormItem>
)}
/>
<LegacyBarButton
className="w-full justify-center"
label="Save Preference"
type="submit"
variant="accent"
/>
</form>
</Form>
);
}API Reference
LegacySwitchProps extends the Radix switch root and adds onLabel and offLabel for the inline text rendered inside the glossy shell.
Also inherits: React.ComponentPropsWithoutRef<typeof SwitchPrimitive.Root>
| Prop | Type | Required |
|---|---|---|
offLabel | string | No |
onLabel | string | No |
Notes
- Use
checkedandonCheckedChangefor controlled state, ordefaultCheckedfor an uncontrolled toggle. onLabelandoffLabeldefault toONandOFF, but you can replace them when a product needs custom wording.- Disabled switches keep the same chrome, which helps locked settings stay visually consistent with active ones.