Switch

A toggle switch component for binary choices, built on Base UI primitives with comprehensive accessibility and dark mode support.

Features

  • Accessible: Built with proper ARIA attributes and keyboard navigation
  • Customizable: Multiple sizes and composable components
  • Form Integration: Works seamlessly with form libraries
  • Dark Mode: Full support for light and dark themes
  • TypeScript: Fully typed with excellent IntelliSense

Installation

The Switch component is included in the @bao-ui/react package.

Basic Usage

import { Switch } from '@bao-ui/react'
 
export function BasicSwitch() {
  return <Switch label="Enable notifications" />
}

With Description

<Switch
  label="Marketing emails"
  description="Receive emails about new products and features."
/>

Sizes

<Switch size="sm" label="Small switch" />
<Switch size="default" label="Default switch" />
<Switch size="lg" label="Large switch" />

States

<Switch label="Default" />
<Switch label="Checked" defaultChecked />
<Switch label="Disabled" disabled />
<Switch label="Disabled & Checked" disabled defaultChecked />

Controlled

import { useState } from 'react'
import { Switch } from '@bao-ui/react'
 
export function ControlledExample() {
  const [checked, setChecked] = useState(false)
 
  return (
    <div className="space-y-4">
      <Switch
        label="Controlled switch"
        checked={checked}
        onCheckedChange={setChecked}
      />
      <div className="text-sm text-muted-foreground">
        Current state: {checked ? 'On' : 'Off'}
      </div>
    </div>
  )
}

Settings Panel Example

Custom Composition

For advanced use cases, you can compose the switch using individual components:

import {
  SwitchRoot,
  SwitchThumb,
  SwitchFieldRoot,
  SwitchLabel,
  SwitchDescription,
} from '@bao-ui/react'
;<SwitchFieldRoot>
  <div className="flex items-center justify-between">
    <div>
      <SwitchLabel>Custom layout switch</SwitchLabel>
      <SwitchDescription>
        This uses individual components for maximum flexibility.
      </SwitchDescription>
    </div>
    <SwitchRoot defaultChecked>
      <SwitchThumb />
    </SwitchRoot>
  </div>
</SwitchFieldRoot>

API Reference

Switch

The main switch component that combines all sub-components for convenience.

PropTypeDefaultDescription
labelstring-Label text for the switch
descriptionstring-Helper text below the switch
size'sm' | 'default' | 'lg''default'Size of the switch
checkedboolean-Controlled checked state
defaultCheckedbooleanfalseDefault checked state
onCheckedChange(checked: boolean) => void-Callback when checked state changes
disabledbooleanfalseWhether the switch is disabled
idstring-HTML id attribute
classNamestring-Additional CSS classes

SwitchRoot

The root switch element.

PropTypeDefaultDescription
size'sm' | 'default' | 'lg''default'Size of the switch
checkedboolean-Controlled checked state
defaultCheckedbooleanfalseDefault checked state
onCheckedChange(checked: boolean) => void-Callback when checked state changes
disabledbooleanfalseWhether the switch is disabled
classNamestring-Additional CSS classes

SwitchThumb

The movable thumb element.

PropTypeDefaultDescription
size'sm' | 'default' | 'lg''default'Size of the thumb
classNamestring-Additional CSS classes

SwitchFieldRoot

Wrapper component for field integration.

PropTypeDefaultDescription
classNamestring-Additional CSS classes

SwitchLabel

Label component for the switch.

PropTypeDefaultDescription
htmlForstring-Associates label with switch
classNamestring-Additional CSS classes

SwitchDescription

Description text component.

PropTypeDefaultDescription
classNamestring-Additional CSS classes

Accessibility

The Switch component follows WAI-ARIA guidelines:

  • Uses proper ARIA attributes (role="switch", aria-checked)
  • Supports keyboard navigation (Space/Enter to toggle)
  • Provides proper focus management
  • Associates labels with the switch control
  • Announces state changes to screen readers

Examples

Form Integration

import { useState } from 'react'
import { Switch } from '@bao-ui/react'
 
export function SettingsForm() {
  const [settings, setSettings] = useState({
    notifications: false,
    marketing: true,
  })
 
  const handleSubmit = e => {
    e.preventDefault()
    console.log('Settings:', settings)
  }
 
  return (
    <form onSubmit={handleSubmit} className="space-y-4">
      <Switch
        label="Email Notifications"
        description="Receive email updates"
        checked={settings.notifications}
        onCheckedChange={checked =>
          setSettings(prev => ({ ...prev, notifications: checked }))
        }
      />
      <Switch
        label="Marketing Emails"
        description="Receive promotional content"
        checked={settings.marketing}
        onCheckedChange={checked =>
          setSettings(prev => ({ ...prev, marketing: checked }))
        }
      />
      <button type="submit">Save Settings</button>
    </form>
  )
}

Without Label

// For inline controls where context is provided elsewhere
<div className="flex items-center space-x-2">
  <span>Dark Mode</span>
  <Switch />
</div>