On/off control for settings, preferences, and feature states.
npx shadcn@latest add @iconiq/r-switch"use client";
import { useState } from "react";
import { Switch } from "@/components/ui/r-switch";
export function SwitchPreview() {
const [enabled, setEnabled] = useState(true);
return (
<div className="flex min-h-[14rem] w-full max-w-md items-center justify-center px-4 py-6">
<Switch
checked={enabled}
id="motion-enabled"
onCheckedChange={setEnabled}
label="Enable motion"
description="Turn animated transitions on or off for this workspace."
/>
</div>
);
}checkedControlled checked state. Pass this when the parent owns the current on or off value.
Type boolean
defaultCheckedInitial checked state for uncontrolled usage. The component keeps its local animation state in sync with this mode too.
Type boolean
onCheckedChangeCalled whenever the switch changes state, after the thumb and fill animation sequence starts.
Type (checked: boolean) => void
labelOptional label rendered beside the switch. When provided with description, both sit inside a native label element linked by htmlFor.
Type React.ReactNode
descriptionOptional helper copy rendered under the label and linked through aria-describedby.
Type React.ReactNode
labelSideControls which side of the switch the label and description block appears on.
Type "left" | "right"·Default right
labelClassNameMerged onto the label text wrapper.
Type string
descriptionClassNameMerged onto the description text wrapper.
Type string
sizeScales the track, thumb, label text, and row gap together.
Type "sm" | "default" | "lg"·Default default
disabledDisables pointer and keyboard interaction, and dims the switch and optional label together.
Type boolean
readOnlyShows the current state without allowing toggles. Useful for locked preference rows.
Type boolean·Default false
requiredForwards native required validation to the hidden input and appends a visual asterisk to the label.
Type boolean·Default false
invalidApplies destructive ring styling and aria-invalid for form validation feedback.
Type boolean·Default false
classNameMerged onto the switch track for local spacing or surface overrides.
Type string
wrapperClassNameMerged onto the outer label wrapper when label or description text is present.
Type string
The switch uses separate motion values for thumb travel, thumb squash, and track fill opacity so the state change feels tactile without becoming noisy.
Built on Radix switch root and thumb primitives while preserving the same motion values for thumb travel, thumb squash, and track fill opacity as the core switch.
Pointer press slightly flattens the thumb before release, then the thumb snaps back with a softer bounce after the state change.
The dark foreground fill fades in as the thumb travels right, rather than swapping track color instantly.
Controlled and uncontrolled usage both keep the thumb animation synchronized with the underlying switch state.
Thumb travel, squash, and fill animations honor prefers-reduced-motion automatically.
The track keeps a fixed left-to-right thumb direction via dir=ltr so RTL layouts do not invert the on state.
Install the exact registry entry shown on the right when you want the component file and its declared runtime dependencies together.
Dependencies: @radix-ui/react-switch, motion.
Installs a Radix switch with the same label, description, size, validation, and readOnly API as the Base UI version.
Uses Radix switch primitives under the exact same Iconiq track, thumb, and press-motion shell as the core switch component.
The generated registry file is /r/r-switch.json.
Contact
Additionally, if you find any bug or issue, feel free to raise an issue.