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
import { useState } from "react";
const [isSelected, setIsSelected] = useState(true);
<Switch isSelected={isSelected} onValueChange={setIsSelected}>
Airplane mode
</Switch>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
<Switch defaultSelected aria-label="Automatic updates" /><Switch defaultSelected aria-label="Automatic updates">
<Switch.Content>
<Switch.Control>
<Switch.Thumb />
</Switch.Control>
</Switch.Content>
</Switch>With Thumb Icon
<Switch thumbIcon={<CheckIcon />}>Enable notifications</Switch><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
<Switch
startContent={<SunIcon />}
endContent={<MoonIcon />}
>
Dark mode
</Switch><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
<Switch description="You will receive notifications for all activity">
Enable notifications
</Switch>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
{/* 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>{/* 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
{/* 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>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