3.1 KiB
Switch Variants (cva config)
Purpose
switchVariants and switchThumbVariants are the two cva (class-variance-authority) configurations that together power every <Switch> render. They are split from switch.tsx into their own module so an ejected source copy under npx shadcn@latest add @suaveplan/switch keeps the cva configurations in a dedicated file. Theme overrides flow through useThemedVariants("Switch", switchVariants), so the runtime cva resolver can be replaced or extended by an active ThemePlugin without touching the component source.
The track and thumb are deliberately kept as separate cva instances so a ThemePlugin can override one independently of the other — for example a glossy-thumb theme with a flat track.
Features
- Three sizes (
sm→h-4 w-7,default→h-5 w-9,lg→h-6 w-11) for both track and thumb. data-[state=checked]:bg-primaryflips the track colour when on.data-[state=checked]:translate-x-*slides the thumb across the track.disabled:cursor-not-allowed disabled:opacity-50for the native disabled state.motion-reduce:transition-nonecollapses both colour + transform transitions forprefers-reduced-motion: reduce.focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2for keyboard-only focus styling.
Usage: Basic Example
import { switchVariants, switchThumbVariants } from "@suaveplan/react-ui";
const trackClassName = switchVariants({ size: "default" });
const thumbClassName = switchThumbVariants({ size: "default" });
Usage: Advanced Example
import { switchVariants, switchThumbVariants, cn } from "@suaveplan/react-ui";
export function CustomSwitch() {
return (
<button
type="button"
role="switch"
aria-checked="false"
data-state="unchecked"
className={cn(switchVariants({ size: "lg" }), "ring-2 ring-accent")}
>
<span
className={cn(
switchThumbVariants({ size: "lg" }),
"bg-accent-foreground"
)}
/>
</button>
);
}
API Reference
switchVariants(props?: { size?: "sm" | "default" | "lg" }): string
Returns the cva-merged class string for the track. Omitted props fall back to the cva defaultVariants (size: "default").
switchThumbVariants(props?: { size?: "sm" | "default" | "lg" }): string
Returns the cva-merged class string for the thumb. The size axis MUST match the track's size — mismatched sizes produce a thumb that overflows or under-fills the track.
Implementation Notes
- Both resolvers are tagged with
componentName: "Switch"/componentName: "SwitchThumb"(non-enumerable, non-writable) viadefineVariants. - The thumb's
translate-x-*per-size value is hard-coded rather than computed — cva is a string-templating library, not a runtime calculator. The math istrack-width − thumb-width − padding-x*2. - The track and thumb size axes are kept symmetric so a single
sizeprop on<Switch>propagates to both. A future change could make them independent if the chassis ever needs anextra-large-thumbshape.