vera logoVera UI
ComponentsForm Components

Switch

A switch component built on Radix UI's Switch primitive that allows users to toggle between on and off states. Perfect for boolean settings, preferences, and feature toggles.

Installation

pnpm add @helgadigitals/vera-ui
npm install @helgadigitals/vera-ui
yarn add @helgadigitals/vera-ui

Usage

import { Switch, Label } from "@helgadigitals/vera-ui"export default function Example() {return (  <div className="flex items-center space-x-2">    <Switch id="airplane-mode" />    <Label htmlFor="airplane-mode">Airplane mode</Label>  </div>)}

Examples

Basic Switch

import { Switch, Label } from "@helgadigitals/vera-ui"export default function BasicExample() {return (  <div className="flex items-center space-x-2">    <Switch id="notifications" />    <Label htmlFor="notifications">Enable notifications</Label>  </div>)}

Controlled Switch

Toggle the switch to see state changes

import { useState } from "react"import { Switch, Label } from "@helgadigitals/vera-ui"export default function ControlledExample() {const [isEnabled, setIsEnabled] = useState(false)return (  <div className="space-y-4">    <div className="flex items-center space-x-2">      <Switch         id="controlled"        checked={isEnabled}        onCheckedChange={setIsEnabled}      />      <Label htmlFor="controlled">        Dark mode ({isEnabled ? 'On' : 'Off'})      </Label>    </div>        <p className="text-sm text-muted-foreground">      Current state: {isEnabled ? 'Enabled' : 'Disabled'}    </p>  </div>)}

Disabled Switch

import { Switch, Label } from "@helgadigitals/vera-ui"export default function DisabledExample() {return (  <div className="space-y-4">    {/* Disabled unchecked */}    <div className="flex items-center space-x-2">      <Switch id="disabled-off" disabled />      <Label htmlFor="disabled-off">Disabled (off)</Label>    </div>    {/* Disabled checked */}    <div className="flex items-center space-x-2">      <Switch id="disabled-on" disabled checked />      <Label htmlFor="disabled-on">Disabled (on)</Label>    </div>  </div>)}

Settings Panel

Privacy Settings

Receive notifications about updates and messages

Receive emails about new features and offers

Help us improve by sharing usage analytics

Allow third-party cookies for enhanced functionality

import { useState } from "react"import { Switch, Label } from "@helgadigitals/vera-ui"export default function SettingsPanelExample() {const [settings, setSettings] = useState({  notifications: true,  marketing: false,  analytics: true,  cookies: false,})const handleSettingChange = (key: string) => (checked: boolean) => {  setSettings(prev => ({ ...prev, [key]: checked }))}return (  <div className="space-y-6 max-w-md">    <h3 className="text-lg font-semibold">Privacy Settings</h3>        <div className="space-y-4">      <div className="flex items-center justify-between">        <div className="space-y-0.5">          <Label htmlFor="notifications" className="text-base">            Push Notifications          </Label>          <p className="text-sm text-muted-foreground">            Receive notifications about updates and messages          </p>        </div>        <Switch          id="notifications"          checked={settings.notifications}          onCheckedChange={handleSettingChange('notifications')}        />      </div>      <div className="flex items-center justify-between">        <div className="space-y-0.5">          <Label htmlFor="marketing" className="text-base">            Marketing Emails          </Label>          <p className="text-sm text-muted-foreground">            Receive emails about new features and offers          </p>        </div>        <Switch          id="marketing"          checked={settings.marketing}          onCheckedChange={handleSettingChange('marketing')}        />      </div>      <div className="flex items-center justify-between">        <div className="space-y-0.5">          <Label htmlFor="analytics" className="text-base">            Analytics          </Label>          <p className="text-sm text-muted-foreground">            Help us improve by sharing usage analytics          </p>        </div>        <Switch          id="analytics"          checked={settings.analytics}          onCheckedChange={handleSettingChange('analytics')}        />      </div>      <div className="flex items-center justify-between">        <div className="space-y-0.5">          <Label htmlFor="cookies" className="text-base">            Third-party Cookies          </Label>          <p className="text-sm text-muted-foreground">            Allow third-party cookies for enhanced functionality          </p>        </div>        <Switch          id="cookies"          checked={settings.cookies}          onCheckedChange={handleSettingChange('cookies')}        />      </div>    </div>  </div>)}

Form Integration

import { useForm, Controller } from "react-hook-form"import { Switch, Label, Button } from "@helgadigitals/vera-ui"export default function FormExample() {const { control, handleSubmit, watch } = useForm({  defaultValues: {    newsletter: false,    terms: false,    marketing: false,  }})const watchTerms = watch('terms')const onSubmit = (data) => {  console.log(data)}return (  <form onSubmit={handleSubmit(onSubmit)} className="space-y-6">    <div className="space-y-4">      <div className="flex items-center space-x-2">        <Controller          name="newsletter"          control={control}          render={({ field }) => (            <Switch              id="newsletter"              checked={field.value}              onCheckedChange={field.onChange}            />          )}        />        <Label htmlFor="newsletter">          Subscribe to newsletter        </Label>      </div>      <div className="flex items-center space-x-2">        <Controller          name="marketing"          control={control}          render={({ field }) => (            <Switch              id="marketing"              checked={field.value}              onCheckedChange={field.onChange}            />          )}        />        <Label htmlFor="marketing">          Receive marketing communications        </Label>      </div>      <div className="flex items-center space-x-2">        <Controller          name="terms"          control={control}          rules={{ required: true }}          render={({ field }) => (            <Switch              id="terms"              checked={field.value}              onCheckedChange={field.onChange}            />          )}        />        <Label htmlFor="terms">          I agree to the terms and conditions *        </Label>      </div>    </div>    <Button       type="submit"       disabled={!watchTerms}      className="w-full"    >      Submit    </Button>  </form>)}

Feature Toggles

Feature Toggles

import { useState } from "react"import { Switch, Label, Card } from "@helgadigitals/vera-ui"export default function FeatureTogglesExample() {const [features, setFeatures] = useState({  betaFeatures: false,  advancedMode: false,  autoSave: true,  realTimeSync: false,})const handleFeatureToggle = (feature: string) => (checked: boolean) => {  setFeatures(prev => ({ ...prev, [feature]: checked }))}return (  <Card className="p-6 max-w-md">    <h3 className="text-lg font-semibold mb-4">Feature Toggles</h3>        <div className="space-y-3">      <div className="flex items-center justify-between">        <Label htmlFor="beta" className="flex-1">          Beta Features        </Label>        <Switch          id="beta"          checked={features.betaFeatures}          onCheckedChange={handleFeatureToggle('betaFeatures')}        />      </div>      <div className="flex items-center justify-between">        <Label htmlFor="advanced" className="flex-1">          Advanced Mode        </Label>        <Switch          id="advanced"          checked={features.advancedMode}          onCheckedChange={handleFeatureToggle('advancedMode')}        />      </div>      <div className="flex items-center justify-between">        <Label htmlFor="autosave" className="flex-1">          Auto Save        </Label>        <Switch          id="autosave"          checked={features.autoSave}          onCheckedChange={handleFeatureToggle('autoSave')}        />      </div>      <div className="flex items-center justify-between">        <Label htmlFor="sync" className="flex-1">          Real-time Sync        </Label>        <Switch          id="sync"          checked={features.realTimeSync}          onCheckedChange={handleFeatureToggle('realTimeSync')}        />      </div>    </div>  </Card>)}

Custom Styling

import { useState } from "react"import { Switch, Label } from "@helgadigitals/vera-ui"export default function CustomStylingExample() {const [isEnabled, setIsEnabled] = useState(false)return (  <div className="space-y-6">    {/* Large switch */}    <div className="flex items-center space-x-3">      <Switch        id="large"        checked={isEnabled}        onCheckedChange={setIsEnabled}        className="h-6 w-11"      />      <Label htmlFor="large" className="text-lg">        Large Switch      </Label>    </div>    {/* Colored switch */}    <div className="flex items-center space-x-2">      <Switch        id="colored"        checked={isEnabled}        onCheckedChange={setIsEnabled}        className="data-[state=checked]:bg-green-600"      />      <Label htmlFor="colored">        Custom Color Switch      </Label>    </div>    {/* Switch with custom thumb */}    <div className="flex items-center space-x-2">      <Switch        id="custom-thumb"        checked={isEnabled}        onCheckedChange={setIsEnabled}        className="[&>span]:bg-blue-600 [&>span]:data-[state=checked]:bg-white"      />      <Label htmlFor="custom-thumb">        Custom Thumb Color      </Label>    </div>  </div>)}

With Icons

import { useState } from "react"import { Moon, Sun } from "lucide-react"import { Switch, Label } from "@helgadigitals/vera-ui"export default function WithIconsExample() {const [isDarkMode, setIsDarkMode] = useState(false)return (  <div className="flex items-center space-x-3">    <Sun className="h-4 w-4" />    <Switch      id="theme-toggle"      checked={isDarkMode}      onCheckedChange={setIsDarkMode}    />    <Moon className="h-4 w-4" />    <Label htmlFor="theme-toggle">      {isDarkMode ? 'Dark' : 'Light'} mode    </Label>  </div>)}

API Reference

Props

The Switch component accepts all props from Radix UI's Switch component:

Prop

Type

Data Attributes

The following data attributes are automatically applied and can be used for styling:

AttributeValuesDescription
data-state"checked" | "unchecked"The checked state of the switch
data-disabledPresent when disabledApplied when the switch is disabled

Switch Thumb

The thumb (movable part) also receives data attributes:

AttributeValuesDescription
data-state"checked" | "unchecked"The checked state of the thumb

Accessibility

The Switch component follows WAI-ARIA guidelines:

  • Keyboard Navigation: Space key toggles the switch state
  • Screen Readers: Proper ARIA attributes and semantic switch element
  • Focus Management: Clear focus indicators with keyboard navigation
  • Labeling: Use proper label elements with htmlFor attribute or aria-label

Labeling: Always provide a clear, descriptive label for switches. Use the label element with the htmlFor attribute pointing to the switch's id.

// Good: Properly labeled switch
<div className="flex items-center space-x-2">
  <Switch id="notifications" />
  <Label htmlFor="notifications">Enable push notifications</Label>
</div>

// Also good: Using aria-label for compact layouts
<Switch aria-label="Toggle dark mode" />

Switch vs Checkbox

Choose Switch for:

  • Settings and preferences that take effect immediately
  • Feature toggles that enable/disable functionality
  • Binary states that represent on/off, enabled/disabled

Choose Checkbox for:

  • Form submissions that require explicit confirmation
  • Multiple selections from a list of options
  • Agreements like terms and conditions

Best Practices

Immediate Effect

Switches should trigger immediate changes:

// Good: Immediate effect
const [notifications, setNotifications] = useState(false)

return (
  <Switch
    checked={notifications}
    onCheckedChange={(checked) => {
      setNotifications(checked)
      // Apply setting immediately
      updateNotificationSettings(checked)
    }}
  />
)

Clear Labels

Use descriptive labels that indicate the action:

// Good: Clear action
<Label htmlFor="auto-save">Enable auto-save</Label>

// Avoid: Ambiguous label
<Label htmlFor="setting">Setting</Label>

Consistent Placement

Maintain consistent switch placement in settings panels:

// Good: Consistent right-aligned switches
<div className="flex items-center justify-between">
  <Label>Setting name</Label>
  <Switch />
</div>

Styling

The Switch component supports custom styling and automatically adapts to your theme:

<Switch className="data-[state=checked]:bg-green-600" />

Common style customizations:

/* Custom switch colors */
.custom-switch {
  @apply data-[state=checked]:bg-blue-600;
}

/* Custom thumb styling */
.custom-switch [data-slot="switch-thumb"] {
  @apply bg-white shadow-lg;
}

/* Large switch variant */
.large-switch {
  @apply h-6 w-11;
}