Wuko
Components

Toggle

A two-state switch built on Radix Switch. Controlled via checked / onChange; supports sm and md sizes, optional inline label, and disabled state. For form-submitted boolean inputs, prefer Checkbox.

Installation

terminal
npx shadcn@latest add @wuko/toggle

Usage

Toggle is fully controlled. Hold the boolean state in your component and pass checked + onChange down. Radix handles the keyboard (Space toggles), focus management, and form integration; your code just decides what the toggle controls.

components/notification-settings.tsx
"use client";

import { useState } from "react";

import { Toggle } from "@/components/ui/toggle";

export function NotificationSettings() {
  const [notifications, setNotifications] = useState(true);
  const [marketing, setMarketing] = useState(false);
  const [smallEnabled, setSmallEnabled] = useState(false);
  return (
    <div className="space-y-3">
      <Toggle
        checked={notifications}
        onChange={setNotifications}
        label="Enable notifications"
      />
      <Toggle
        checked={marketing}
        onChange={setMarketing}
        label="Marketing emails"
      />
      <Toggle
        checked={true}
        onChange={() => {}}
        disabled
        label="Disabled (on)"
      />
      <Toggle
        checked={smallEnabled}
        onChange={setSmallEnabled}
        size="sm"
        label="Small"
      />
    </div>
  );
}

Props

PropTypeDefaultDescription
checkedbooleanRequired. Whether the toggle is on. Toggle is fully controlled. Manage this state in your component.
onChange(checked: boolean) => voidRequired. Called with the new state when the user toggles via click, Space key, or label click.
labelstringOptional inline label rendered next to the switch. HTML5 implicit label association: clicking the label area toggles the switch.
size"sm" | "md""md"Two sizes available: sm for compact inline contexts (settings rows, table cells), md for standalone settings or form fields.
disabledbooleanfalseDisables interaction. Dims the entire wrapper (label + switch) via opacity-50.
classNamestringTailwind classes merged onto the wrapping label element.
...restComponentPropsWithoutRef<typeof Switch.Root>Forwarded to the underlying Radix Switch.Root: id, name, value, form, aria-*, data-*, etc. Excludes the controlled-mode pair (checked, defaultChecked, onCheckedChange) to prevent control-mode mixing.