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-uinpm install @helgadigitals/vera-uiyarn add @helgadigitals/vera-uiUsage
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:
| Attribute | Values | Description |
|---|---|---|
data-state | "checked" | "unchecked" | The checked state of the switch |
data-disabled | Present when disabled | Applied when the switch is disabled |
Switch Thumb
The thumb (movable part) also receives data attributes:
| Attribute | Values | Description |
|---|---|---|
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
labelelements withhtmlForattribute oraria-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;
}Select
A select component built on Radix UI's Select primitive that allows users to choose a single value from a dropdown list of options. Features keyboard navigation, accessibility, and customizable styling.
Textarea
A textarea component for multi-line text input with automatic resizing support. Built with accessibility and user experience in mind, featuring modern styling and seamless integration with forms.