Forms
Switch
Accessible toggle switch built on react-aria-components, styled with the quebi design system. The on state fills the track with brand teal while a white thumb slides across; supports labels, controlled state, and disabled.
forminputtogglebooleaninteractive
States
Off, on, and disabled.
Without label
The toggle on its own.
Controlled
Source
Copy this into your project. Resolve its dependencies from the registryDependencies in the component's API entry.
"use client"
import { Switch as SwitchPrimitive, type SwitchProps } from "react-aria-components"
import { Label } from "@/components/field"
import { cn } from "@/lib/utils"
/**
* Switch — quebi design system
*
* Built on react-aria-components. A 44x24 toggle: the off track is a subtle
* cyan-tinted surface, the on track fills with brand teal, and a white thumb
* slides 20px to the right when selected. Focus uses the quebi teal ring.
*/
export function Switch({ children, className, ...props }: SwitchProps) {
return (
<SwitchPrimitive
{...props}
data-slot="control"
className={cn(
// Inline-flex so the Switch only takes the width it needs. Indicator
// first, then any children (label / description) to the right.
"group inline-flex items-center gap-3 disabled:cursor-not-allowed disabled:opacity-50",
className,
)}
style={({ defaultStyle }) => ({
...defaultStyle,
WebkitTapHighlightColor: "transparent",
})}
>
{(values) => (
<>
<span
data-slot="indicator"
className={cn(
// 44x24 track, pill-shaped.
"relative isolate inline-flex h-6 w-11 shrink-0 rounded-full border",
"transition-colors duration-200",
"border-cyan-500/30 bg-cyan-500/10",
values.isSelected && "border-quebi-brand bg-quebi-brand",
values.isFocusVisible &&
"ring-2 ring-quebi-brand/50 ring-offset-2 ring-offset-quebi-bg",
)}
>
<span
aria-hidden="true"
className={cn(
// 20x20 thumb, 2px inset from top-left, slides 20px right when on.
"pointer-events-none absolute top-0.5 left-0.5 size-5 rounded-full bg-white shadow-quebi-glow",
"transition-transform duration-200",
values.isSelected && "translate-x-5",
)}
/>
</span>
{typeof children === "function" ? (
children(values)
) : typeof children === "string" ? (
<SwitchLabel>{children}</SwitchLabel>
) : (
children
)}
</>
)}
</SwitchPrimitive>
)
}
export function SwitchLabel(props: React.ComponentProps<typeof Label>) {
return <Label elementType="span" {...props} />
}