Switch
Migration guide for Switch from HeroUI v2 to v3
Refer to the v3 Switch documentation for complete API reference, styling guide, and advanced examples. This guide only focuses on migrating from HeroUI v2.
Structure Changes
In v2, Switch used a simple structure with children as label:
import { Switch } from "@heroui/react";
export default function App() {
return <Switch>Enable notifications</Switch>;
}
In v3, Switch requires compound components:
import { Switch, Label } from "@heroui/react";
export default function App() {
return (
<Switch>
<Switch.Content>
<Switch.Control>
<Switch.Thumb />
</Switch.Control>
Enable notifications
</Switch.Content>
</Switch>
);
}
Key Changes
1. Component Structure
v2: Simple Switch with children as label
v3: Compound components (Switch.Content, Switch.Control, Switch.Thumb) with Label component
2. Prop Changes
| v2 Prop | v3 Location | Notes |
|---|---|---|
onValueChange | onChange | Renamed event handler |
size | size | Still exists on root (sm | md | lg) |
label | — | Use Label component |
color | — | Removed (use Tailwind CSS) |
thumbIcon | — | Use Switch.Icon inside Switch.Thumb |
startContent | — | Customize control directly |
endContent | — | Customize control directly |
classNames | — | Use className props on individual components |
disableAnimation | — | Removed (animations handled differently) |
3. New Components
SwitchGroup- For grouping multiple switchesSwitch.Content- The clickable label wrapping the control andLabelSwitch.Icon- For icons inside the thumb
Migration Examples
Controlled Switch
v2
```tsx
import { useState } from "react";
const [isSelected, setIsSelected] = useState(true);
<Switch isSelected={isSelected} onValueChange={setIsSelected}>
Airplane mode
</Switch>
```
v3
```tsx
import { useState } from "react";
const [isSelected, setIsSelected] = useState(true);
<Switch isSelected={isSelected} onChange={setIsSelected}>
<Switch.Content>
<Switch.Control>
<Switch.Thumb />
</Switch.Control>
Airplane mode
</Switch.Content>
</Switch>
```
Without Label
v2
```tsx
<Switch defaultSelected aria-label="Automatic updates" />
```
v3
```tsx
<Switch defaultSelected aria-label="Automatic updates">
<Switch.Content>
<Switch.Control>
<Switch.Thumb />
</Switch.Control>
</Switch.Content>
</Switch>
```
With Thumb Icon
v2
```tsx
<Switch thumbIcon={<CheckIcon />}>Enable notifications</Switch>
```
v3
```tsx
<Switch>
<Switch.Content>
<Switch.Control>
<Switch.Thumb>
<Switch.Icon>
<CheckIcon />
</Switch.Icon>
</Switch.Thumb>
</Switch.Control>
Enable notifications
</Switch.Content>
</Switch>
```
With Start/End Content
v2
```tsx
<Switch
startContent={<SunIcon />}
endContent={<MoonIcon />}
>
Dark mode
</Switch>
```
v3
```tsx
<Switch>
<Switch.Content>
<Switch.Control className="flex items-center gap-2">
<SunIcon />
<Switch.Thumb />
<MoonIcon />
</Switch.Control>
Dark mode
</Switch.Content>
</Switch>
```
With Label and Description
v2
```tsx
<Switch description="You will receive notifications for all activity">
Enable notifications
</Switch>
```
v3
```tsx
import { Switch, Label, Description } from "@heroui/react";
<Switch>
<Switch.Content>
<Switch.Control>
<Switch.Thumb />
</Switch.Control>
Enable notifications
</Switch.Content>
<Description>You will receive notifications for all activity</Description>
</Switch>
```
Sizes and Colors
v2
```tsx
{/* Sizes */}
<div className="flex gap-4">
<Switch size="sm">Small</Switch>
<Switch size="md">Medium</Switch>
<Switch size="lg">Large</Switch>
</div>
{/* Colors */}
<Switch color="primary">Primary</Switch>
<Switch color="success">Success</Switch>
<Switch color="danger">Danger</Switch>
```
v3
```tsx
{/* Sizes */}
<div className="flex gap-4">
<Switch size="sm">
<Switch.Content>
<Switch.Control>
<Switch.Thumb />
</Switch.Control>
Small
</Switch.Content>
</Switch>
<Switch size="md">
<Switch.Content>
<Switch.Control>
<Switch.Thumb />
</Switch.Control>
Medium
</Switch.Content>
</Switch>
<Switch size="lg">
<Switch.Content>
<Switch.Control>
<Switch.Thumb />
</Switch.Control>
Large
</Switch.Content>
</Switch>
</div>
{/* Colors - Use Tailwind CSS classes */}
<Switch>
<Switch.Content>
<Switch.Control className="data-[selected=true]:bg-accent">
<Switch.Thumb />
</Switch.Control>
Primary
</Switch.Content>
</Switch>
<Switch>
<Switch.Content>
<Switch.Control className="data-[selected=true]:bg-success">
<Switch.Thumb />
</Switch.Control>
Success
</Switch.Content>
</Switch>
<Switch>
<Switch.Content>
<Switch.Control className="data-[selected=true]:bg-danger">
<Switch.Thumb />
</Switch.Control>
Danger
</Switch.Content>
</Switch>
```
Switch Group
v2
```tsx
{/* No built-in group component in v2 */}
<div className="flex flex-col gap-2">
<Switch name="notifications">Allow Notifications</Switch>
<Switch name="marketing">Marketing emails</Switch>
</div>
```
v3
```tsx
import { SwitchGroup } from "@heroui/react";
<SwitchGroup>
<Switch name="notifications">
<Switch.Content>
<Switch.Control>
<Switch.Thumb />
</Switch.Control>
Allow Notifications
</Switch.Content>
</Switch>
<Switch name="marketing">
<Switch.Content>
<Switch.Control>
<Switch.Thumb />
</Switch.Control>
Marketing emails
</Switch.Content>
</Switch>
</SwitchGroup>
```
Component Anatomy
The v3 Switch follows this structure:
Switch (Root)
├── Switch.Content (the clickable label)
│ ├── Switch.Control
│ │ └── Switch.Thumb
│ │ └── Switch.Icon (optional)
│ └── Label
├── Description (optional, sibling)
└── FieldError (optional, sibling)
For groups:
SwitchGroup
├── Switch
│ ├── Switch.Content
│ │ ├── Switch.Control
│ │ │ └── Switch.Thumb
│ │ └── Label
│ └── Description (optional)
└── Switch
├── Switch.Content
│ ├── Switch.Control
│ │ └── Switch.Thumb
│ └── Label
└── Description (optional)
Important Notes
Event Handler
- v2:
onValueChangeprop - v3:
onChangeprop (same signature:(isSelected: boolean) => void)
Label Handling
- v2: Children were used as label
- v3: Label goes inside
Switch.Content(the clickable label);Description/FieldErrorare siblings ofSwitch.Content
Icons
- v2:
thumbIconprop for icon inside thumb,startContent/endContentfor icons outside - v3: Use
Switch.IconinsideSwitch.Thumbfor thumb icon, customizeSwitch.Controlfor start/end content
Summary
- Component Structure: Must use compound components (
Switch.Content,Switch.Control,Switch.Thumb) - Clickable Label: Use
Switch.Contentto wrapSwitch.ControlandLabel; placeDescription/FieldErroras siblings ofSwitch.Content - Label Handling: Children no longer used as label - use
Labelcomponent insideSwitch.Content - Event Handler:
onValueChange→onChange - Styling Props Removed:
color- use Tailwind CSS - Icon Props Removed:
thumbIcon,startContent,endContent- use components or customize directly - ClassNames Removed: Use
classNameprops on individual components - New Components:
SwitchGroupfor grouping switches,Switch.Contentas the clickable label wrapping the control andLabel
Local source: vendor/en/react/migration/(components)/switch.mdx
Generated from the pinned HeroUI v3 commit with internal links and previews adapted for JGuang.