Files
suaveplan/packages/ui/react/react-ui/src/components/switch/switch.variants.md
2026-05-27 23:47:53 +01:00

3.1 KiB
Raw Blame History

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-primary flips the track colour when on.
  • data-[state=checked]:translate-x-* slides the thumb across the track.
  • disabled:cursor-not-allowed disabled:opacity-50 for the native disabled state.
  • motion-reduce:transition-none collapses both colour + transform transitions for prefers-reduced-motion: reduce.
  • focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 for 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) via defineVariants.
  • 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 is track-width − thumb-width − padding-x*2.
  • The track and thumb size axes are kept symmetric so a single size prop on <Switch> propagates to both. A future change could make them independent if the chassis ever needs an extra-large-thumb shape.