Switch

An accessible toggle switch for instant on/off settings. Built on Radix UI.

Inline with label

Settings row (label left, switch right)

Automatically connect to known networks.

Allow nearby devices to pair.

Disabled

Installation

pnpm
pnpm dlx @hex-core/cli add switch

Switch with description

Canonical preference row — primary label inline with the switch and a secondary description beneath. The whole row is clickable via the htmlFor pairing.

tsx
<div className="flex items-start justify-between gap-4 rounded-lg border border-input p-4">
  <div className="grid gap-0.5">
    <Label htmlFor="marketing-emails" className="font-medium">Marketing emails</Label>
    <p className="text-sm text-muted-foreground">
      Get product updates, occasional changelog highlights, and the monthly newsletter.
    </p>
  </div>
  <Switch id="marketing-emails" defaultChecked />
</div>

Controlled with form integration

Bind the switch to parent state for forms that need to read or POST the value. The same pattern adapts to react-hook-form by passing field.value / field.onChange instead.

tsx
import { useState } from "react";

export function PrivacyToggle() {
  const [isPublic, setIsPublic] = useState(true);

  return (
    <form
      className="grid gap-3"
      onSubmit={(e) => {
        e.preventDefault();
        // POST { visibility: isPublic ? "public" : "private" }
      }}
    >
      <div className="flex items-center justify-between gap-4">
        <Label htmlFor="profile-public">Public profile</Label>
        <Switch
          id="profile-public"
          checked={isPublic}
          onCheckedChange={setIsPublic}
        />
      </div>
      <p className="text-xs text-muted-foreground">
        {isPublic
          ? "Anyone with the link can view your profile."
          : "Only invited collaborators can view your profile."}
      </p>
      <Button type="submit" size="sm" className="justify-self-start">Save</Button>
    </form>
  );
}

API Reference

PropTypeDefaultDescription
checked
booleanControlled checked state
defaultChecked
booleanDefault for uncontrolled
onCheckedChange
functionCallback: (checked: boolean) => void
disabled
booleanfalseDisable the switch
className
stringAdditional CSS classes

AI Guidance

When to use

Use for settings that take effect immediately: dark mode, notifications, feature toggles.

When not to use

Don't use for form submissions (use Checkbox). Don't use for mutually exclusive options (use RadioGroup).

Common mistakes

  • Using for form fields that need explicit submit
  • Missing Label
  • Wrapping Switch in a <form> and treating it as a form field — Switch fires onCheckedChange immediately, not on submit. For form-bound binary fields with explicit submit, use Checkbox.

Accessibility

Always pair with Label. Radix handles role='switch' and aria-checked.

Related components

Token budget: 250

Verified against @hex-core/components@1.12.0