For the complete documentation index, see llms.txt. Markdown variants are available by appending .md to any URL or sending an Accept: text/markdown header. An agent skill is available at /.well-known/agent-skills/site-skill.md.
Home

Switch

A binary toggle control with smooth thumb animation and distinct on/off audio feedback.

Enabled
import { useState } from "react";
import { Label } from "@/components/ui/label";
import { Switch } from "@/components/ui/switch";

export const SwitchDemo = () => {
  const [notifications, setNotifications] = useState(true);

  return (
    <div className="flex flex-col gap-6">
      {/* Basic */}
      <div className="flex items-center gap-2">
        <Switch id="sw-basic" defaultChecked sounds />
        <Label htmlFor="sw-basic">Airplane mode</Label>
      </div>
      {/* Controlled with status */}
      <div className="flex items-center justify-between rounded-lg border p-4">
        <div className="flex flex-col gap-0.5">
          <Label htmlFor="sw-notifications" className="text-sm font-medium">Push notifications</Label>
          <span className="text-muted-foreground text-xs">{notifications ? "Enabled" : "Disabled"}</span>
        </div>
        <Switch
          id="sw-notifications"
          checked={notifications}
          onCheckedChange={setNotifications}
          sounds
        />
      </div>
      {/* Group */}
      <div className="flex flex-col gap-3 rounded-lg border p-4">
        {[
          { defaultChecked: true, id: "sw-email", label: "Email digest" },
          { defaultChecked: false, id: "sw-sms", label: "SMS alerts" },
          { defaultChecked: true, id: "sw-slack", label: "Slack messages" },
        ].map(({ id, label, defaultChecked }) => (
          <div key={id} className="flex items-center justify-between">
            <Label htmlFor={id}>{label}</Label>
            <Switch id={id} defaultChecked={defaultChecked} sounds />
          </div>
        ))}
      </div>
      {/* Disabled states */}
      <div className="flex items-center gap-6">
        <div className="flex items-center gap-2">
          <Switch id="sw-dis-off" disabled />
          <Label htmlFor="sw-dis-off" className="text-muted-foreground">Off (disabled)</Label>
        </div>
        <div className="flex items-center gap-2">
          <Switch id="sw-dis-on" disabled defaultChecked />
          <Label htmlFor="sw-dis-on" className="text-muted-foreground">On (disabled)</Label>
        </div>
      </div>
    </div>
  );
};

With label

Pair with Label using a shared id / htmlFor for accessible click target.

<div className="flex items-center gap-2">
  <Switch id="airplane" defaultChecked />
  <Label htmlFor="airplane">Airplane mode</Label>
</div>

Controlled

const [checked, setChecked] = useState(false);
 
<Switch checked={checked} onCheckedChange={setChecked} />

Settings row pattern

<div className="flex items-center justify-between rounded-lg border p-4">
  <div className="flex flex-col gap-0.5">
    <Label htmlFor="notifs" className="font-medium">Push notifications</Label>
    <span className="text-muted-foreground text-xs">Receive alerts on your device</span>
  </div>
  <Switch id="notifs" defaultChecked />
</div>

With sounds

Pass sounds to play toggleOn when switched on and toggleOff when switched off.

<Switch sounds />

Props

PropTypeDefaultDescription
checkedboolean—Controlled checked state
defaultCheckedbooleanfalseUncontrolled initial state
onCheckedChange(checked: boolean) => void—Callback on state change
disabledbooleanfalseDisables interaction
soundsbooleanfalsePlays toggleOn / toggleOff audio

Usage

import { Switch } from "@/components/ui/switch";
 
<Switch defaultChecked onCheckedChange={(v) => console.log(v)} />

Specs

# Mint — Switch Specs
 
## Component
- name: switch
- file: registry/mint/switch.tsx
- installs to: components/ui/switch.tsx
- dependencies: radix-ui
- registryDependencies: none
 
## What is it
A binary toggle control built on Radix Switch.Root + Switch.Thumb. Use it to
represent an on/off setting that takes effect immediately without a form submit.
Prefer Switch over a Checkbox when the action is instant; do not use it when
the user must confirm the change before it applies.
 
## Visual identity
Pill-shaped track (rounded-full) transitions from a muted input colour when
unchecked to the theme primary when checked. A small circular thumb slides
across with a smooth CSS transition, giving clear directional feedback.
Mint's 1.25rem radius base keeps the track corners proportionate.
 
## Design tokens
--input: oklch(0.88 0.04 155 / 60%) / oklch(0.32 0.05 155 / 40%)    — track colour when unchecked
--primary: oklch(0.5 0.14 155) / oklch(0.62 0.15 155)     — track colour when checked
--background: oklch(1 0 0) / oklch(0.145 0 0)      — thumb fill
--ring: oklch(0.5 0.14 155) / oklch(0.62 0.15 155)        — focus ring colour
--destructive: oklch(0.55 0.25 15) / oklch(0.704 0.191 22.216) — invalid border
 
## Sub-components
- Switch        → root toggle (SwitchPrimitive.Root); renders track, handles interaction
- Switch.Thumb  → sliding circle (SwitchPrimitive.Thumb); moves on state change
 
## States
- unchecked:      track is --input (soft translucent green)
- checked:        track becomes --primary; thumb translates 1rem (translate-x-4)
- focus-visible:  3px ring in --ring/50, border switches to --ring
- disabled:       opacity-50, cursor-not-allowed, pointer-events blocked
- aria-invalid:   destructive/20 ring (light) / destructive/40 ring (dark) + destructive border
 
## Conventions
- Always pair with a Label via matching id / htmlFor for accessible click target
- Place label after the switch in DOM order (switch left, label right) to match natural reading flow
- In settings-row layouts use justify-between with the switch on the trailing side
- sounds / haptic: GIN Design exclusive — plays toggleOn audio when switched on and toggleOff when switched off; pass sounds prop to enable
- Sub-components expose data-slot="switch" and data-slot="switch-thumb" for CSS targeting
- No variants defined — visual appearance is controlled entirely by theme tokens

Installation

GIN Design Plugin
$ npx shadcn add https://gin-design.vercel.app/switch