# Switch

> A smooth switch for product settings and control panels.

A shadcn/ui block from the [@wensity](https://ui.wensity.com/components) registry, listed on [shadcn.exchange](https://shadcn.exchange/r/wensity/switch).

- Page, with a live preview: https://shadcn.exchange/r/wensity/switch
- Screenshot: https://abzjhwgwpdpz7ua5.public.blob.vercel-storage.com/shots/wensity/switch-light-54d6c014064d4173.png
- Registry item: https://raw.githubusercontent.com/wensity/registry/main/switch.json
- Categories: UI Primitives, wensity, free
- Listed: 2026-10-13, source last changed 2026-10-13

## Install

```bash
npx shadcn@latest add https://raw.githubusercontent.com/wensity/registry/main/switch.json
```

Run it in a project that has shadcn/ui set up. It adds the files below and installs what they depend on.

## Dependencies

- npm packages: `@base-ui/react`, `clsx`, `tailwind-merge`

## Notes from the registry

Free Wensity component. Installs to @components/wensity/switch.tsx. For Pro components and updates, use pnpm dlx wensity@latest add switch.

## Files

### `registry/wensity/lib/utils.ts`

```ts
import { type ClassValue, clsx } from "clsx";
import { twMerge } from "tailwind-merge";

export function cn(...inputs: ClassValue[]) {
  return twMerge(clsx(inputs));
}
```

### `registry/wensity/switch.tsx`

```tsx
"use client";

import * as React from "react";
import { Switch as BaseSwitch } from "@base-ui/react/switch";
import { cn } from "@/lib/utils";

const wensityCardSurfaceClass = cn(
  "relative isolate overflow-hidden rounded-[var(--primitive-radius-surface)]",
  "border border-[var(--border)] bg-[var(--primitive-surface-elevated)]",
  "[box-shadow:var(--primitive-shadow-raised)]",
);

/**
 * CSS rules for Switch animation slots. Re-keyed to Base UI `data-checked` /
 * `data-unchecked` attributes so they light up automatically from `BaseSwitch.Root`.
 *
 * These rules ship in the Wensity token CSS block the CLI writes into your
 * stylesheet, so this file injects no runtime `<style>` tag.
 */

export type SwitchSize = "sm" | "md" | "lg";
export type SwitchVariant = "minimal" | "elevated" | "segmented" | "power";

export type SwitchChangeHandler = (
  checked: boolean,
  eventDetails?: unknown,
) => void;

export interface SwitchProps
  extends Omit<
    React.ComponentPropsWithoutRef<typeof BaseSwitch.Root>,
    "className" | "onCheckedChange" | "render"
  > {
  onCheckedChange?: SwitchChangeHandler;
  label?: React.ReactNode;
  description?: React.ReactNode;
  error?: React.ReactNode;
  switchSize?: SwitchSize;
  variant?: SwitchVariant;
  labelPosition?: "left" | "right";
  fullWidth?: boolean;
  className?: string;
  containerClassName?: string;
  controlClassName?: string;
  labelClassName?: string;
  descriptionClassName?: string;
}

export interface SwitchGroupProps
  extends React.HTMLAttributes<HTMLFieldSetElement> {
  label?: React.ReactNode;
  description?: React.ReactNode;
  error?: React.ReactNode;
  children: React.ReactNode;
  divided?: boolean;
}

export interface SwitchCardProps extends SwitchProps {
  leading?: React.ReactNode;
  /** Static status label when trailingOn/trailingOff are not set. */
  trailing?: React.ReactNode;
  /** Status label when the switch is on. */
  trailingOn?: React.ReactNode;
  /** Status label when the switch is off. */
  trailingOff?: React.ReactNode;
}

export interface SwitchSettingsGroupProps {
  title: string;
  description?: React.ReactNode;
  children: React.ReactNode;
  className?: string;
}

const trackSizes: Record<SwitchSize, string> = {
  sm: "h-5 w-9",
  md: "h-6 w-11",
  lg: "h-7 w-[3.25rem]",
};

const knobSizes: Record<SwitchSize, string> = {
  sm: "size-4",
  md: "size-5",
  lg: "size-6",
};

const segmentedSizes: Record<SwitchSize, string> = {
  sm: "h-7 w-[4.5rem] text-[10px]",
  md: "h-8 w-[5.25rem] text-[11px]",
  lg: "h-9 w-24 text-xs",
};

const iconSizes: Record<SwitchSize, string> = {
  sm: "size-7",
  md: "size-8",
  lg: "size-9",
};

const labelSizes: Record<SwitchSize, string> = {
  sm: "text-[13px]",
  md: "text-sm",
  lg: "text-[15px]",
};

const rowGap: Record<SwitchSize, string> = {
  sm: "gap-3",
  md: "gap-3.5",
  lg: "gap-4",
};

const controlOffset: Record<SwitchSize, string> = {
  sm: "mt-px",
  md: "mt-0.5",
  lg: "mt-0.5",
};

/**
 * Focus ring applied via Base UI's `data-focused` / native `:focus-visible` on the
 * button-role span. Uses primitive ring token.
 */
const focusRing = cn(
  "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--primitive-ring)]",
  "focus-visible:ring-offset-2 focus-visible:ring-offset-[var(--background)]",
);

/**
 * ≥44px touch target for small pill variant. Positioned as a pseudo overlay so it
 * expands the click surface without shifting layout (PRIM-A11Y-004).
 */
const smTouchTarget =
  "before:absolute before:inset-1/2 before:-translate-x-1/2 before:-translate-y-1/2 before:h-11 before:w-11 before:content-['']";

/** Recessed rail — visible against page bg in both themes. */
const trackOff = cn(
  "border border-transparent",
  "bg-[color-mix(in_srgb,var(--foreground)_8%,var(--background))]",
  "dark:bg-[color-mix(in_srgb,var(--foreground)_14%,var(--background))]",
  "data-hover:bg-[color-mix(in_srgb,var(--foreground)_12%,var(--background))]",
  "dark:data-hover:bg-[color-mix(in_srgb,var(--foreground)_18%,var(--background))]",
);

/** Active pill rail — solid foreground fill styled via `--primitive-control-solid` fallback. */
const trackOnPill = cn(
  "border border-[color-mix(in_srgb,var(--foreground)_10%,transparent)]",
  "bg-[var(--primitive-control-solid)]",
  "dark:border-[color-mix(in_srgb,var(--foreground)_24%,transparent)]",
);

/** Active power rail — full foreground fill; icon provides contrast. */
const trackOnPower = cn(
  "border border-[color-mix(in_srgb,var(--foreground)_10%,transparent)]",
  "bg-[var(--primitive-control-solid)]",
);

const trackOnError = cn(
  "border border-[var(--primitive-destructive-border)]",
  "bg-[var(--primitive-destructive)]",
);

/** Thumb stays on the solid-foreground token so it reads against the solid rail. */
const knobBase = cn(
  "pointer-events-none rounded-full bg-[var(--primitive-control-solid-foreground)] transform-gpu",
  "shadow-[0_1px_1px_rgba(0,0,0,0.14),0_0_0_1px_rgba(0,0,0,0.05)]",
  "dark:shadow-[0_1px_2px_rgba(0,0,0,0.34),0_0_0_1px_rgba(255,255,255,0.08)]",
);

const knobElevated = cn(
  "shadow-[0_1px_2px_rgba(0,0,0,0.16),0_0_0_1px_rgba(0,0,0,0.05)]",
  "dark:shadow-[0_1px_2px_rgba(0,0,0,0.38),0_0_0_1px_rgba(255,255,255,0.10)]",
);

/** Segmented / power shell (off). */
const shellOff = cn(
  "border border-[var(--border-strong)]",
  "bg-[color-mix(in_srgb,var(--foreground)_6%,var(--background))]",
  "dark:bg-[color-mix(in_srgb,var(--foreground)_10%,var(--background))]",
);

/** Segmented shell when on (non-error). */
const shellOn = cn(
  "border border-[color-mix(in_srgb,var(--foreground)_12%,transparent)]",
  "bg-[color-mix(in_srgb,var(--foreground)_9%,var(--background))]",
  "dark:border-[color-mix(in_srgb,var(--foreground)_14%,transparent)] dark:bg-[color-mix(in_srgb,var(--foreground)_16%,var(--background))]",
);

function knobClasses(elevatedKnob: boolean) {
  return cn(knobBase, elevatedKnob && knobElevated);
}

function resolvePillTrack(
  checked: boolean,
  error?: React.ReactNode,
  mode: "pill" | "power" = "pill",
) {
  if (error && checked) return trackOnError;
  if (checked) return mode === "power" ? trackOnPower : trackOnPill;
  return trackOff;
}

function resolveSegmentedShell(checked: boolean, error?: React.ReactNode) {
  if (error && checked) {
    return cn(
      "border border-[var(--primitive-destructive-border)]",
      "bg-[var(--primitive-destructive-surface)]",
    );
  }
  if (checked) return shellOn;
  return shellOff;
}

function SwitchCheckIcon({
  className,
  slot,
}: {
  className?: string;
  slot?: string;
}) {
  return (
    <svg
      aria-hidden="true"
      viewBox="0 0 16 16"
      fill="none"
      data-slot={slot}
      className={cn("size-3.5", className)}
    >
      <path
        d="M3.5 8.2 6.4 11.1 12.6 4.9"
        stroke="currentColor"
        strokeWidth="1.85"
        strokeLinecap="round"
        strokeLinejoin="round"
        pathLength={1}
      />
    </svg>
  );
}

function SwitchPowerIcon({
  checked,
  error,
}: {
  checked: boolean;
  error?: React.ReactNode;
}) {
  return (
    <span className="relative size-3.5">
      <span
        data-slot="switch-power-icon"
        data-active={!checked}
        aria-hidden="true"
      >
        <svg
          viewBox="0 0 16 16"
          fill="none"
          className="size-3.5 text-[var(--muted-foreground)]"
        >
          <path
            d="M8 3.25v3.5"
            stroke="currentColor"
            strokeWidth="1.65"
            strokeLinecap="round"
          />
          <path
            d="M5.35 5.35a3.65 3.65 0 1 0 5.3 0"
            stroke="currentColor"
            strokeWidth="1.65"
            strokeLinecap="round"
          />
        </svg>
      </span>
      <span
        data-slot="switch-power-icon"
        data-active={checked}
        aria-hidden="true"
      >
        <SwitchCheckIcon
          slot="switch-power-check"
          className={
            error
              ? "text-[var(--primitive-destructive-foreground)]"
              : "text-[var(--primitive-control-solid-foreground)]"
          }
        />
      </span>
    </span>
  );
}

const segmentActiveText = "text-[var(--foreground)]";
const segmentInactiveText = "text-[var(--muted-foreground)]";

type SwitchControlRenderProps = {
  checked: boolean;
  disabled?: boolean;
  error?: React.ReactNode;
  switchSize: SwitchSize;
  variant: SwitchVariant;
  className?: string;
};

/** Builds the class string + children for the BaseSwitch.Root visual. */
function buildSwitchControl({
  checked,
  disabled,
  error,
  switchSize,
  variant,
  className,
}: SwitchControlRenderProps) {
  if (variant === "segmented") {
    return {
      className: cn(
        "relative grid shrink-0 grid-cols-2 items-center overflow-hidden rounded-full p-0.5",
        resolveSegmentedShell(checked, error),
        focusRing,
        disabled && "opacity-45",
        segmentedSizes[switchSize],
        className,
      ),
      children: (
        <>
          <span
            data-slot="switch-segment-indicator"
            aria-hidden="true"
            className={cn(
              "absolute inset-y-0.5 left-0.5 w-[calc(50%-2px)] rounded-full",
              checked && error
                ? cn(
                    "bg-[var(--primitive-destructive)]",
                    "shadow-[0_1px_1px_rgba(0,0,0,0.18)]",
                  )
                : knobBase,
            )}
          />
          <span
            data-slot="switch-segment-label"
            className={cn(
              "relative z-[2] text-center font-medium tracking-[-0.01em]",
              checked ? segmentInactiveText : segmentActiveText,
            )}
          >
            Off
          </span>
          <span
            data-slot="switch-segment-label"
            className={cn(
              "relative z-[2] text-center font-medium tracking-[-0.01em]",
              checked
                ? error
                  ? "text-[var(--primitive-destructive-foreground)]"
                  : segmentActiveText
                : segmentInactiveText,
            )}
          >
            On
          </span>
        </>
      ),
    };
  }

  if (variant === "power") {
    return {
      className: cn(
        "relative inline-flex shrink-0 items-center justify-center rounded-full",
        resolvePillTrack(checked, error, "power"),
        focusRing,
        iconSizes[switchSize],
        disabled && "opacity-45",
        switchSize === "sm" && smTouchTarget,
        className,
      ),
      children: <SwitchPowerIcon checked={checked} error={error} />,
    };
  }

  const elevatedKnob = variant === "elevated";

  return {
    className: cn(
      "relative inline-flex shrink-0 items-center rounded-full p-0.5",
      resolvePillTrack(checked, error),
      focusRing,
      trackSizes[switchSize],
      disabled && "opacity-45",
      switchSize === "sm" && smTouchTarget,
      className,
    ),
    children: (
      <BaseSwitch.Thumb
        data-slot="switch-knob"
        data-size={switchSize}
        aria-hidden="true"
        className={cn(knobClasses(elevatedKnob), knobSizes[switchSize])}
      />
    ),
  };
}

/**
 * Base UI–backed Switch. Renders `BaseSwitch.Root` (a `<span role="switch">` plus
 * hidden `<input>`) styled as track/knob/segmented/power. Emits Base UI's
 * `data-checked` / `data-unchecked` / `data-disabled` for CSS state hooks.
 */
export const Switch = React.forwardRef<HTMLButtonElement, SwitchProps>(
  (
    {
      id,
      className,
      containerClassName,
      controlClassName,
      labelClassName,
      descriptionClassName,
      label,
      description,
      error,
      switchSize = "md",
      variant = "minimal",
      labelPosition = "right",
      fullWidth = true,
      checked,
      defaultChecked = false,
      disabled,
      onCheckedChange,
      inputRef,
      "aria-describedby": ariaDescribedBy,
      ...props
    },
    ref,
  ) => {
    const reactId = React.useId();
    const switchId = id ?? `ui-switch-${reactId}`;
    const descriptionId = description ? `${switchId}-description` : undefined;
    const errorId = error ? `${switchId}-error` : undefined;
    const isControlled = checked !== undefined;
    const [uncontrolledChecked, setUncontrolledChecked] =
      React.useState(defaultChecked);
    const isChecked = isControlled ? checked : uncontrolledChecked;
    const describedBy =
      [ariaDescribedBy, errorId, descriptionId].filter(Boolean).join(" ") ||
      undefined;
    const hasCopy = Boolean(label || description || error);
    const alignStart = Boolean(description || error);

    const handleCheckedChange = React.useCallback(
      (next: boolean, eventDetails: unknown) => {
        if (!isControlled) setUncontrolledChecked(next);
        onCheckedChange?.(next, eventDetails);
      },
      [isControlled, onCheckedChange],
    );

    const rendered = buildSwitchControl({
      checked: isChecked,
      disabled,
      error,
      switchSize,
      variant,
      className: controlClassName,
    });

    const control = (
      <BaseSwitch.Root
        ref={ref}
        id={switchId}
        checked={isChecked}
        disabled={disabled}
        onCheckedChange={handleCheckedChange}
        inputRef={inputRef}
        aria-invalid={error ? true : undefined}
        aria-describedby={describedBy}
        data-slot="switch-control"
        data-variant={variant}
        className={rendered.className}
        {...props}
      >
        {rendered.children}
      </BaseSwitch.Root>
    );

    const copy = hasCopy ? (
      <span className="min-w-0 flex-1">
        {label ? (
          typeof label === "string" || typeof label === "number" ? (
            <span
              className={cn(
                "block font-medium leading-snug tracking-[-0.015em] text-[var(--foreground)]",
                labelSizes[switchSize],
                disabled && "text-[var(--muted-foreground)]",
                labelClassName,
              )}
            >
              {label}
            </span>
          ) : (
            label
          )
        ) : null}
        {description ? (
          <span
            id={descriptionId}
            className={cn(
              "mt-1 block text-[12px] leading-5 text-[var(--muted-foreground)]",
              descriptionClassName,
            )}
          >
            {description}
          </span>
        ) : null}
        {error ? (
          <span
            id={errorId}
            className="mt-1 block text-[12px] leading-5 text-[var(--primitive-destructive)]"
          >
            {error}
          </span>
        ) : null}
      </span>
    ) : null;

    return (
      <label data-wensity-primitive=""
        data-slot="switch"
        htmlFor={switchId}
        className={cn(
          "group/switch relative flex cursor-pointer select-none",
          alignStart ? "items-start" : "items-center",
          rowGap[switchSize],
          fullWidth ? "w-full" : "w-fit",
          disabled && "cursor-not-allowed",
          labelPosition === "left" && "justify-between",
          containerClassName,
          className,
        )}
      >
        {labelPosition === "left" ? (
          <>
            {copy}
            <span className={cn("shrink-0", alignStart && controlOffset[switchSize])}>
              {control}
            </span>
          </>
        ) : (
          <>
            <span className={cn("shrink-0", alignStart && controlOffset[switchSize])}>
              {control}
            </span>
            {copy}
          </>
        )}
      </label>
    );
  },
);

Switch.displayName = "Switch";

export function SwitchGroup({
  label,
  description,
  error,
  children,
  divided = true,
  className,
  ...props
}: SwitchGroupProps) {
  const reactId = React.useId();
  const descriptionId = description
    ? `ui-switch-group-${reactId}-description`
    : undefined;
  const errorId = error ? `ui-switch-group-${reactId}-error` : undefined;

  return (
    <fieldset
      aria-describedby={[descriptionId, errorId].filter(Boolean).join(" ") || undefined}
      className={cn("space-y-3", className)}
      {...props}
    >
      {label || description ? (
        <div className="space-y-1">
          {label ? (
            <legend className="text-sm font-semibold tracking-[-0.015em] text-[var(--foreground)]">
              {label}
            </legend>
          ) : null}
          {description ? (
            <p
              id={descriptionId}
              className="text-[12px] leading-5 text-[var(--muted-foreground)]"
            >
              {description}
            </p>
          ) : null}
        </div>
      ) : null}
      <div
        className={cn(
          divided && wensityCardSurfaceClass,
          divided &&
            "[&>[data-slot=switch]]:border-b [&>[data-slot=switch]]:border-[var(--border)] [&>[data-slot=switch]]:px-4 [&>[data-slot=switch]]:py-3.5 [&>[data-slot=switch]:last-child]:border-b-0",
          !divided && "space-y-1",
        )}
      >
        {children}
      </div>
      {error ? (
        <p id={errorId} className="text-[12px] leading-5 text-[var(--primitive-destructive)]">
          {error}
        </p>
      ) : null}
    </fieldset>
  );
}

export function SwitchSettingsGroup({
  title,
  description,
  children,
  className,
}: SwitchSettingsGroupProps) {
  return (
    <section className={cn("flex min-h-0 min-w-0 flex-col gap-2.5", className)}>
      <header className="min-h-11 px-0.5">
        <h3 className="font-[family-name:var(--primitive-font-display)] text-[13px] font-semibold leading-5 tracking-[-0.015em] text-[var(--foreground)]">
          {title}
        </h3>
        {description ? (
          <p className="mt-0.5 line-clamp-2 text-[12px] leading-5 text-[var(--muted-foreground)]">
            {description}
          </p>
        ) : (
          <p
            className="mt-0.5 text-[12px] leading-5 text-transparent"
            aria-hidden="true"
          >
            &nbsp;
          </p>
        )}
      </header>
      <div
        className={cn(
          wensityCardSurfaceClass,
          "[&_[data-slot=switch]]:border-b [&_[data-slot=switch]]:border-[var(--border)]",
          "[&_[data-slot=switch]:last-child]:border-b-0",
        )}
      >
        {children}
      </div>
    </section>
  );
}

export function SwitchCard({
  leading,
  trailing,
  trailingOn,
  trailingOff,
  label,
  description,
  error,
  className,
  switchSize = "md",
  variant = "minimal",
  disabled,
  checked,
  defaultChecked = false,
  onCheckedChange,
  id,
  inputRef,
  labelPosition: _labelPosition,
  fullWidth: _fullWidth,
  containerClassName: _containerClassName,
  controlClassName: _controlClassName,
  labelClassName: _labelClassName,
  descriptionClassName: _descriptionClassName,
  ...props
}: SwitchCardProps) {
  const reactId = React.useId();
  const switchId = id ?? `ui-switch-card-${reactId}`;
  const descriptionId = description ? `${switchId}-description` : undefined;
  const errorId = error ? `${switchId}-error` : undefined;
  const isControlled = checked !== undefined;
  const [uncontrolledChecked, setUncontrolledChecked] =
    React.useState(defaultChecked);
  const isChecked = isControlled ? checked : uncontrolledChecked;
  const trailingLabel =
    trailingOn !== undefined || trailingOff !== undefined
      ? isChecked
        ? trailingOn
        : trailingOff
      : trailing;
  const describedBy =
    [errorId, descriptionId].filter(Boolean).join(" ") || undefined;
  const hasAnimatedTrailing =
    trailingOn !== undefined || trailingOff !== undefined;
  const [trailingSwapping, setTrailingSwapping] = React.useState(false);
  const prevCheckedRef = React.useRef(isChecked);

  React.useEffect(() => {
    if (!hasAnimatedTrailing) {
      prevCheckedRef.current = isChecked;
      return;
    }
    if (prevCheckedRef.current === isChecked) return;
    prevCheckedRef.current = isChecked;
    setTrailingSwapping(true);
    const timeoutId = window.setTimeout(() => setTrailingSwapping(false), 220);
    return () => window.clearTimeout(timeoutId);
  }, [hasAnimatedTrailing, isChecked]);

  const handleCheckedChange = React.useCallback(
    (next: boolean, eventDetails: unknown) => {
      if (!isControlled) setUncontrolledChecked(next);
      onCheckedChange?.(next, eventDetails);
    },
    [isControlled, onCheckedChange],
  );

  const rendered = buildSwitchControl({
    checked: isChecked,
    disabled,
    error,
    switchSize,
    variant,
  });

  return (
    <label data-wensity-primitive=""
      data-slot="switch"
      htmlFor={switchId}
      className={cn(
        "group/switch flex min-h-16 w-full cursor-pointer select-none items-center gap-3.5 px-4 py-3",
        "transition-[background-color] duration-200 ease-[var(--primitive-ease,cubic-bezier(0.16,1,0.3,1))] motion-reduce:transition-none",
        !disabled && "hover:bg-[var(--primitive-surface-hover)]",
        "has-[[data-checked]]:bg-[var(--primitive-surface-selected)]",
        disabled && "cursor-not-allowed opacity-45 hover:bg-transparent",
        className,
      )}
    >
      {leading ? (
        <span
          className={cn(
            "switch-card-icon grid size-9 shrink-0 place-items-center rounded-[var(--primitive-radius-control-sm)]",
            "border border-[var(--border)]",
            "bg-[color-mix(in_srgb,var(--foreground)_4%,var(--background))]",
            "text-[var(--muted-foreground)]",
            "transition-[border-color,background-color,color] duration-[220ms] ease-[var(--primitive-ease,cubic-bezier(0.16,1,0.3,1))] motion-reduce:transition-none",
            "[&_svg]:size-[17px]",
            "group-has-[[data-checked]]/switch:border-[color-mix(in_srgb,var(--foreground)_12%,transparent)]",
            "group-has-[[data-checked]]/switch:bg-[color-mix(in_srgb,var(--foreground)_7%,var(--background))]",
            "group-has-[[data-checked]]/switch:text-[var(--foreground)]",
            disabled && "opacity-80",
          )}
        >
          {leading}
        </span>
      ) : null}

      <span className="min-w-0 flex-1">
        {label ? (
          <span
            className={cn(
              "block font-medium leading-snug tracking-[-0.015em] text-[var(--foreground)]",
              labelSizes[switchSize],
              disabled && "text-[var(--muted-foreground)]",
            )}
          >
            {label}
          </span>
        ) : null}
        {description ? (
          <span
            id={descriptionId}
            className="mt-0.5 line-clamp-2 block text-[12px] leading-[1.45] text-[var(--muted-foreground)]"
          >
            {description}
          </span>
        ) : null}
        {error ? (
          <span
            id={errorId}
            className="mt-1 block text-[12px] leading-5 text-[var(--primitive-destructive)]"
          >
            {error}
          </span>
        ) : null}
      </span>

      <span className="flex shrink-0 items-center gap-2.5 pl-1">
        {trailingLabel ? (
          <span
            aria-live="polite"
            data-slot="switch-card-trailing"
            data-swapping={trailingSwapping ? "true" : undefined}
            className={cn(
              "inline-flex min-w-[3.25rem] items-center justify-center rounded-[var(--primitive-radius-control-sm)] border border-[var(--border)]",
              "bg-[color-mix(in_srgb,var(--foreground)_3%,var(--background))] px-1.5 py-0.5",
              "text-[10px] font-medium tracking-[0.01em] text-[var(--muted-foreground)]",
              "group-has-[[data-checked]]/switch:border-[color-mix(in_srgb,var(--foreground)_10%,transparent)]",
              "group-has-[[data-checked]]/switch:text-[var(--foreground)]",
            )}
          >
            {trailingLabel}
          </span>
        ) : null}
        <BaseSwitch.Root
          id={switchId}
          checked={isChecked}
          disabled={disabled}
          onCheckedChange={handleCheckedChange}
          inputRef={inputRef}
          aria-invalid={error ? true : undefined}
          aria-describedby={describedBy}
          data-slot="switch-control"
          data-variant={variant}
          className={rendered.className}
          {...props}
        >
          {rendered.children}
        </BaseSwitch.Root>
      </span>
    </label>
  );
}
```
