Switchv1.1.2Documentation Under Review
A toggle control that allows users to switch between on and off states.
Installation
Install the switch component via your package manager:
npm install @pmi/catalyst-switchUsage
Import the switch components:
import { SwitchRoot, SwitchThumb } from '@pmi/catalyst-switch';Examples
Basic Switch
A simple toggle switch with checked and unchecked states.
Switch Sizes
Switch supports three size variants: small, medium, and large.
Disabled State
Switches can be disabled to prevent user interaction.
With Label
Integrate switch with labels for better accessibility and user experience.
With Label Sizes
All switch sizes work seamlessly with corresponding label sizes.
Layout Variant
Switch and label can be arranged in different layouts, including reversed order.
With Label and SubText
Complete form control with label and helper text.
Custom Thumb
Use the asChild prop to customize the switch thumb with icons or other elements.
Custom Styled (Infinity Design)
Custom switch styling with the Infinity design system's aqua color palette, including size-specific variants.
Themes
Component API
SwitchRoot
The root container for the switch component.
| Prop | Type | Default | Description |
|---|---|---|---|
size | 'sm' | 'md' | 'lg' | 'md' | Size variant of the switch |
checked | boolean | - | Controlled checked state |
defaultChecked | boolean | - | Uncontrolled default checked state |
disabled | boolean | false | Whether the switch is disabled |
required | boolean | false | Whether the switch is required in a form |
name | string | - | Name attribute for form submission |
value | string | 'on' | Value attribute for form submission |
onCheckedChange | (checked: boolean) => void | - | Callback when checked state changes |
className | string | - | Additional CSS classes |
id | string | - | HTML id attribute for label association |
unstyled | boolean | false | Disables all default CVA/Tailwind styling, only applies className. |
SwitchThumb
The thumb element that moves when the switch is toggled.
| Prop | Type | Default | Description |
|---|---|---|---|
asChild | boolean | false | Use Slot to render custom thumb element |
className | string | - | Additional CSS classes |
unstyled | boolean | false | Disables all default CVA/Tailwind styling, only applies className. |
Size Variants
Custom Styling
Infinity Design System
The Infinity design uses aqua colors for switches with size-specific thumb translations. Here are the complete styling patterns using CVA (class-variance-authority):
SwitchRoot Styles with CVA
import { cva } from 'class-variance-authority';
const switchRootInfinityVariants = cva(
[
// Base styles
'border border-solid outline-pmi-aqua-500',
// Checked state
'data-[state=checked]:border-pmi-aqua-500',
'data-[state=checked]:bg-pmi-aqua-500',
'data-[state=checked]:hover:bg-pmi-aqua-800',
'data-[state=checked]:hover:border-pmi-aqua-800',
// Unchecked state
'data-[state=unchecked]:border-neutral-500',
'data-[state=unchecked]:bg-white',
'data-[state=unchecked]:hover:bg-pmi-aqua-100',
// Dark mode - checked
'dark:data-[state=checked]:bg-pmi-aqua-500',
'dark:data-[state=checked]:hover:bg-pmi-aqua-800',
'dark:data-[state=checked]:border-pmi-aqua-500',
'dark:data-[state=checked]:hover:border-pmi-aqua-800',
// Dark mode - unchecked
'dark:data-[state=unchecked]:border-neutral-500',
'dark:data-[state=unchecked]:bg-neutral-800',
'dark:data-[state=unchecked]:hover:bg-pmi-aqua-800',
'dark:outline-pmi-aqua-500',
],
{
variants: {
size: {
// Small and large need custom translate values
sm: ['[&_span]:data-[state=checked]:translate-x-[15px]'],
md: undefined, // Uses default from component
lg: ['[&_span]:data-[state=checked]:translate-x-[15px]'],
},
},
defaultVariants: {
size: 'md',
},
}
);
// Usage
<SwitchRoot
size="sm"
className={switchRootInfinityVariants({ size: 'sm' })}
>
<SwitchThumb className={switchThumbInfinityStyles} />
</SwitchRoot>Important: Size-specific variants are needed because sm and lg switches require custom translate-x values (15px) for proper thumb positioning, while md uses the component's default translation (20px).
SwitchThumb Styles
// Thumb colors for Infinity design
const switchThumbInfinityStyles = cn(
'bg-pmi-aqua-500',
'data-[state=checked]:bg-white',
'dark:bg-white',
'dark:data-[state=checked]:bg-white'
);Accessibility
Keyboard Navigation
- Space - Toggle the switch state
- Enter - Toggle the switch state
- Tab - Move focus to or from the switch
ARIA Attributes
The Switch component automatically includes proper ARIA attributes:
role="switch"- Identifies the element as a switcharia-checked- Indicates the current checked statearia-disabled- Indicates if the switch is disabled- Associated label via
idandhtmlForattributes
Screen Reader Support
- State changes are announced (on/off)
- Labels are properly associated with switches
- Disabled state is announced
Best Practices
- Always provide a label - Use the Label component or aria-label for context
- Use clear labels - Describe what the switch controls
- Provide helper text - Add SubText for additional context when needed
- Indicate disabled state - Make it clear when a switch cannot be toggled
- Use appropriate sizing - Smaller sizes for product interfaces, larger for touch
Integration Patterns
Controlled State
import { SwitchRoot, SwitchThumb } from '@pmi/catalyst-switch';
import { useState } from 'react';
export default function ControlledSwitch() {
const [checked, setChecked] = useState(false);
return (
<SwitchRoot checked={checked} onCheckedChange={setChecked}>
<SwitchThumb />
</SwitchRoot>
);
}Form Integration
<form onSubmit={handleSubmit}>
<SwitchRoot name="notifications" value="enabled">
<SwitchThumb />
</SwitchRoot>
</form>With React Hook Form
import { useForm, Controller } from 'react-hook-form';
function MyForm() {
const { control } = useForm();
return (
<Controller
name="notifications"
control={control}
render={({ field }) => (
<SwitchRoot
checked={field.value}
onCheckedChange={field.onChange}
>
<SwitchThumb />
</SwitchRoot>
)}
/>
);
}