# Switch

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

> For the complete documentation index, see [llms.txt](/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](/.well-known/agent-skills/site-skill.md).





<ComponentThemeTabs>
  <ThemeTab name="mint">
    <PreviewWithCode name="switch">
      <SwitchDemo />
    </PreviewWithCode>
  </ThemeTab>

  <ThemeTab name="berries">
    <PreviewWithCode name="switch">
      <SwitchDemo />
    </PreviewWithCode>
  </ThemeTab>

  <ThemeTab name="citrine">
    <PreviewWithCode name="switch">
      <SwitchDemo />
    </PreviewWithCode>
  </ThemeTab>

  <ThemeTab name="cinnamon">
    <PreviewWithCode name="switch">
      <SwitchDemo />
    </PreviewWithCode>
  </ThemeTab>
</ComponentThemeTabs>

## With label [#with-label]

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

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

## Controlled [#controlled]

```tsx
const [checked, setChecked] = useState(false);

<Switch checked={checked} onCheckedChange={setChecked} />
```

## Settings row pattern [#settings-row-pattern]

```tsx
<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 [#with-sounds]

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

```tsx
<Switch sounds />
```

## Props [#props]

| Prop              | Type                         | Default | Description                          |
| ----------------- | ---------------------------- | ------- | ------------------------------------ |
| `checked`         | `boolean`                    | —       | Controlled checked state             |
| `defaultChecked`  | `boolean`                    | `false` | Uncontrolled initial state           |
| `onCheckedChange` | `(checked: boolean) => void` | —       | Callback on state change             |
| `disabled`        | `boolean`                    | `false` | Disables interaction                 |
| `sounds`          | `boolean`                    | `false` | Plays `toggleOn` / `toggleOff` audio |

## Usage [#usage]

```tsx
import { Switch } from "@/components/ui/switch";

<Switch defaultChecked onCheckedChange={(v) => console.log(v)} />
```

## Specs [#specs]

```md
# 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 [#installation]

<CommandBox componentName="switch" className="mt-2" />
