Skip to main content

Installation

npx shadcn@latest add switch

Usage

import { Switch } from "@/components/ui/switch"
<Switch />

Component API

Switch

Toggle switch component built on Radix UI Switch.
function Switch({
  className,
  size = "default",
  ...props
}: React.ComponentProps<typeof SwitchPrimitive.Root> & {
  size?: "sm" | "default"
})
Props:
  • size - Switch size ("sm" | "default")
  • checked - Controlled checked state
  • defaultChecked - Default checked state
  • onCheckedChange - Callback when checked state changes
  • disabled - Disables the switch
  • aria-invalid - Shows error state styling

Implementation

The switch includes a thumb that animates:
<SwitchPrimitive.Root
  className="inline-flex items-center rounded-full border shadow-xs transition-all"
>
  <SwitchPrimitive.Thumb
    className="block rounded-full bg-background transition-transform data-[state=checked]:translate-x-[calc(100%-2px)]"
  />
</SwitchPrimitive.Root>

Examples

Basic Switch

<Switch />

With Label

Switch with associated label:
<div className="flex items-center space-x-2">
  <Switch id="airplane-mode" />
  <Label htmlFor="airplane-mode">Airplane Mode</Label>
</div>

Controlled Switch

function ControlledSwitch() {
  const [checked, setChecked] = React.useState(false)

  return (
    <div className="flex items-center space-x-2">
      <Switch
        id="controlled"
        checked={checked}
        onCheckedChange={setChecked}
      />
      <Label htmlFor="controlled">
        {checked ? "On" : "Off"}
      </Label>
    </div>
  )
}

With Description

Switch with label and description:
<div className="flex items-center justify-between">
  <div className="space-y-0.5">
    <Label htmlFor="marketing">Marketing emails</Label>
    <p className="text-sm text-muted-foreground">
      Receive emails about new products and features.
    </p>
  </div>
  <Switch id="marketing" />
</div>

Disabled State

<Switch disabled />
<Switch disabled checked />

Invalid State

Show validation error:
<div className="space-y-2">
  <div className="flex items-center space-x-2">
    <Switch id="terms" aria-invalid />
    <Label htmlFor="terms">Accept terms and conditions</Label>
  </div>
  <p className="text-sm text-destructive">You must accept the terms</p>
</div>

Different Sizes

<div className="flex items-center gap-4">
  <Switch size="sm" />
  <Switch size="default" />
</div>

Settings Panel

Practical example:
function SettingsPanel() {
  const [settings, setSettings] = React.useState({
    marketing: false,
    security: true,
    notifications: false,
  })

  return (
    <div className="space-y-4">
      <div className="flex items-center justify-between">
        <div>
          <Label>Marketing emails</Label>
          <p className="text-sm text-muted-foreground">
            Receive emails about new products
          </p>
        </div>
        <Switch
          checked={settings.marketing}
          onCheckedChange={(checked) =>
            setSettings({ ...settings, marketing: checked })
          }
        />
      </div>
      <div className="flex items-center justify-between">
        <div>
          <Label>Security alerts</Label>
          <p className="text-sm text-muted-foreground">
            Get notified about account activity
          </p>
        </div>
        <Switch
          checked={settings.security}
          onCheckedChange={(checked) =>
            setSettings({ ...settings, security: checked })
          }
        />
      </div>
    </div>
  )
}

Form Integration

With React Hook Form:
import { useForm } from "react-hook-form"

function FormExample() {
  const { register, handleSubmit } = useForm()

  return (
    <form onSubmit={handleSubmit(onSubmit)}>
      <div className="flex items-center space-x-2">
        <Switch {...register("notifications")} />
        <Label>Enable notifications</Label>
      </div>
    </form>
  )
}

Choice Card

Clickable card-style switch:
<label
  htmlFor="choice"
  className="flex items-center justify-between rounded-lg border p-4 cursor-pointer hover:bg-accent"
>
  <div>
    <div className="font-medium">Enable feature</div>
    <div className="text-sm text-muted-foreground">
      This enables the advanced features
    </div>
  </div>
  <Switch id="choice" />
</label>

Accessibility

  • Uses role="switch" semantics
  • Keyboard accessible (Space to toggle)
  • Proper ARIA attributes
  • Focus visible states
  • Associated labels via htmlFor
  • Screen reader announcements

API Reference

See the Radix UI Switch documentation for complete API reference.

Build docs developers (and LLMs) love