For the complete documentation index, see llms.txt. Markdown variants are available by appending .md to documentation URLs. Homepage markdown is available at /llms.md/content.md. An agent skill is available at /.well-known/agent-skills/site-skill.md.

Switch

The Switch component from this design system, built on Base UI.

Installation

$ pnpm dlx shadcn@latest add @cobalt/switch

Shape and size

shape is pill (default) or rectangle. size is lg (56x32), default (42x24) or sm (28x16). The thumb, inset and travel scale together.

States and label

Use checked with onCheckedChange to control the switch, or defaultChecked to leave it uncontrolled. Pair it with a Label through htmlFor so clicking the text toggles it. A disabled switch dims to 50%.

Source

"use client";

import { Switch as SwitchPrimitive } from "@base-ui/react/switch";
import { cn } from "cn";

const sizes = {
  sm: {
    track:
      "h-4 w-7 data-checked:shadow-[inset_0_1px_0_0_rgb(255_255_255/0.25),inset_0_0_0_0.5px_oklch(from_var(--primary)_calc(l_+_0.08)_c_h)]",
    thumb:
      "start-0.5 top-0.5 size-3 data-checked:translate-x-3 rtl:data-checked:-translate-x-3",
    chip: "size-[5px] border-[0.25px] shadow-[0_2px_2px_0_rgb(0_0_0/0.03)]",
    rectangle: ["rounded-[3px]", "rounded-[1px]", "rounded-[0.5px]"],
  },
  default: {
    track:
      "h-6 w-[42px] data-checked:shadow-[inset_0_1.5px_0_0_rgb(255_255_255/0.25),inset_0_0_0_0.75px_oklch(from_var(--primary)_calc(l_+_0.08)_c_h)]",
    thumb:
      "start-[3px] top-[3px] size-[18px] data-checked:translate-x-[18px] rtl:data-checked:-translate-x-[18px]",
    chip: "size-[7.5px] border-[0.375px] shadow-[0_3px_3px_0_rgb(0_0_0/0.03)]",
    rectangle: ["rounded-[4.5px]", "rounded-[1.5px]", "rounded-[0.75px]"],
  },
  lg: {
    track:
      "h-8 w-14 data-checked:shadow-[inset_0_2px_0_0_rgb(255_255_255/0.25),inset_0_0_0_1px_oklch(from_var(--primary)_calc(l_+_0.08)_c_h)]",
    thumb:
      "start-1 top-1 size-6 data-checked:translate-x-6 rtl:data-checked:-translate-x-6",
    chip: "size-[10px] border-[0.5px] shadow-[0_4px_4px_0_rgb(0_0_0/0.03)]",
    rectangle: ["rounded-[6px]", "rounded-[2px]", "rounded-[1px]"],
  },
};

function Switch({
  className,
  size = "default",
  shape = "pill",
  ...props
}: SwitchPrimitive.Root.Props & {
  size?: "sm" | "default" | "lg";
  shape?: "pill" | "rectangle";
}) {
  const s = sizes[size];
  return (
    <SwitchPrimitive.Root
      data-slot="switch"
      data-size={size}
      data-shape={shape}
      className={cn(
        "peer group/switch relative inline-flex shrink-0 cursor-pointer border-0 bg-[var(--surface-strong,var(--input))] p-0 outline-none transition-colors duration-200 ease-[ease] motion-reduce:transition-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background aria-invalid:ring-3 aria-invalid:ring-destructive/20 data-checked:bg-[image:var(--gradient-button-primary-default,linear-gradient(180deg,oklch(from_var(--primary)_calc(l_+_0.08)_c_h),var(--primary)))] data-disabled:cursor-not-allowed data-disabled:opacity-50",
        s.track,
        shape === "pill" ? "rounded-full" : s.rectangle[0],
        className
      )}
      {...props}
    >
      <SwitchPrimitive.Thumb
        data-slot="switch-thumb"
        className={cn(
          "pointer-events-none absolute flex items-center justify-center bg-[image:linear-gradient(180deg,var(--switch-thumb-start,var(--primary-foreground))_43.837%,var(--switch-thumb-end,var(--muted)))] shadow-[0_3px_3px_0_rgb(0_0_0/0.03),0_0.75px_0_0_rgb(0_0_0/0.05)] transition-transform duration-200 ease-[ease] motion-reduce:transition-none",
          s.thumb,
          shape === "pill" ? "rounded-full" : s.rectangle[1]
        )}
      >
        <span
          aria-hidden="true"
          className={cn(
            "border-solid border-[color:var(--switch-chip-border,var(--border))] bg-[image:linear-gradient(to_top,var(--surface-raised,var(--background))_43.837%,var(--muted))] group-data-checked/switch:border-primary group-data-checked/switch:bg-[image:linear-gradient(to_top,var(--switch-on-chip-start,var(--primary))_43.837%,var(--switch-on-chip-end,var(--primary)))]",
            s.chip,
            shape === "pill" ? "rounded-full" : s.rectangle[2]
          )}
        />
      </SwitchPrimitive.Thumb>
    </SwitchPrimitive.Root>
  );
}

export { Switch };