Switch

Accessible toggle switch with controlled/uncontrolled support and form integration.

Switch

The Switch component is a fully accessible toggle switch (also called a checkbox switch). It supports controlled and uncontrolled modes, works in forms, and has proper ARIA semantics. Use it for binary on/off settings.

Switch is unstyled. Use SwitchThumb to render the visual toggle indicator inside Switch.


Features

  • Controlled/uncontrolled modes
  • Form integration (works with form submission)
  • Optional SwitchThumb for visual indicator
  • ARIA switch semantics (role="switch", aria-checked)
  • Keyboard support (Space to toggle)
  • Disabled state support

Usage

import { Switch, SwitchThumb } from '@loke/ui/switch';

export default function Example() {
  const [checked, setChecked] = React.useState(false);

  return (
    <div className="flex items-center gap-2">
      <Switch checked={checked} onCheckedChange={setChecked}>
        <SwitchThumb className="w-6 h-6 bg-gray-400 rounded-full transition-transform" />
      </Switch>
      <label>{checked ? 'On' : 'Off'}</label>
    </div>
  );
}

Props

Switch

Prop

Type

SwitchThumb

Prop

Type


Examples

Off

Notifications are disabled

Basic toggle

<Switch defaultChecked>
  <SwitchThumb className="w-5 h-5 bg-white rounded-full shadow transition-transform group-data-[state=checked]:translate-x-5" />
</Switch>

With label

<div className="flex items-center gap-3">
  <Switch id="notifications" defaultChecked>
    <SwitchThumb className="w-6 h-6 bg-gray-400 rounded-full" />
  </Switch>
  <label htmlFor="notifications">Enable notifications</label>
</div>

In a form

<form onSubmit={handleSubmit}>
  <label>
    <Switch name="marketing-emails" defaultChecked>
      <SwitchThumb className="w-5 h-5 bg-gray-400 rounded-full" />
    </Switch>
    Send me marketing emails
  </label>
  <button type="submit">Save</button>
</form>

Styled with Tailwind

<Switch defaultChecked>
  <SwitchThumb
    className={`
      inline-block w-5 h-5 rounded-full
      transition-all duration-200 ease-out
      data-[state=unchecked]:bg-gray-300
      data-[state=checked]:bg-green-600
    `}
  />
</Switch>

Keyboard Navigation

  • Space: Toggle the switch
  • Tab: Move focus to the switch
  • Shift+Tab: Move focus away from the switch

Accessibility

  • Switch has role="switch" and aria-checked="true|false"
  • Disabled switches have aria-disabled="true"
  • Labels should use htmlFor to associate with Switch's ID
  • SwitchThumb has data-state="checked|unchecked" for styling based on state

Form Integration

Switch can be used directly in forms:

<form>
  <Switch name="terms" required>
    <SwitchThumb />
  </Switch>
  <button type="submit">Agree and sign up</button>
</form>

The switch will submit its value (default "on") when checked, or no value when unchecked.


Best practices

  • Always provide a label (either via <label htmlFor> or aria-label)
  • Style SwitchThumb with data-[state=checked] and data-[state=unchecked] selectors
  • Keep the switch itself small and the clickable area reasonable (40–44px minimum)
  • Use disabled state sparingly; explain why the switch is disabled if unclear
  • Test with keyboard navigation (Space key) to ensure toggle works