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.Control>
<Switch.Thumb />
</Switch.Control>
<Switch.Content>
<Label>Enable notifications</Label>
</Switch.Content>
</Switch>
);
}Key Changes
1. Component Structure
v2: Simple Switch with children as label
v3: Compound components (Switch.Control, Switch.Thumb, Switch.Content) 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- Container for label and descriptionSwitch.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.Control>
<Switch.Thumb />
</Switch.Control>
<Switch.Content>
<Label>Airplane mode</Label>
</Switch.Content>
</Switch>Without Label
<Switch defaultSelected aria-label="Automatic updates" /><Switch defaultSelected aria-label="Automatic updates">
<Switch.Control>
<Switch.Thumb />
</Switch.Control>
</Switch>With Thumb Icon
<Switch thumbIcon={<CheckIcon />}>Enable notifications</Switch><Switch>
<Switch.Control>
<Switch.Thumb>
<Switch.Icon>
<CheckIcon />
</Switch.Icon>
</Switch.Thumb>
</Switch.Control>
<Switch.Content>
<Label>Enable notifications</Label>
</Switch.Content>
</Switch>With Start/End Content
<Switch
startContent={<SunIcon />}
endContent={<MoonIcon />}
>
Dark mode
</Switch><Switch>
<Switch.Control className="flex items-center gap-2">
<SunIcon />
<Switch.Thumb />
<MoonIcon />
</Switch.Control>
<Switch.Content>
<Label>Dark mode</Label>
</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.Control>
<Switch.Thumb />
</Switch.Control>
<Switch.Content>
<Label>Enable notifications</Label>
<Description>You will receive notifications for all activity</Description>
</Switch.Content>
</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.Control>
<Switch.Thumb />
</Switch.Control>
<Switch.Content>
<Label>Small</Label>
</Switch.Content>
</Switch>
<Switch size="md">
<Switch.Control>
<Switch.Thumb />
</Switch.Control>
<Switch.Content>
<Label>Medium</Label>
</Switch.Content>
</Switch>
<Switch size="lg">
<Switch.Control>
<Switch.Thumb />
</Switch.Control>
<Switch.Content>
<Label>Large</Label>
</Switch.Content>
</Switch>
</div>
{/* Colors - Use Tailwind CSS classes */}
<Switch>
<Switch.Control className="data-[selected=true]:bg-accent">
<Switch.Thumb />
</Switch.Control>
<Switch.Content>
<Label>Primary</Label>
</Switch.Content>
</Switch>
<Switch>
<Switch.Control className="data-[selected=true]:bg-success">
<Switch.Thumb />
</Switch.Control>
<Switch.Content>
<Label>Success</Label>
</Switch.Content>
</Switch>
<Switch>
<Switch.Control className="data-[selected=true]:bg-danger">
<Switch.Thumb />
</Switch.Control>
<Switch.Content>
<Label>Danger</Label>
</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.Control>
<Switch.Thumb />
</Switch.Control>
<Switch.Content>
<Label>Allow Notifications</Label>
</Switch.Content>
</Switch>
<Switch name="marketing">
<Switch.Control>
<Switch.Thumb />
</Switch.Control>
<Switch.Content>
<Label>Marketing emails</Label>
</Switch.Content>
</Switch>
</SwitchGroup>Component Anatomy
The v3 Switch follows this structure:
Switch (Root)
├── Switch.Control
│ └── Switch.Thumb
│ └── Switch.Icon (optional)
└── Switch.Content (optional)
├── Label (optional)
└── Description (optional)For groups:
SwitchGroup
├── Switch
│ ├── Switch.Control
│ │ └── Switch.Thumb
│ └── Switch.Content
│ ├── Label
│ └── Description (optional)
└── Switch
├── Switch.Control
│ └── Switch.Thumb
└── Switch.Content
├── 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: Use
Labelcomponent insideSwitch.Content; optionally addDescriptionalongside it
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.Control,Switch.Thumb,Switch.Content) - Content Container: Use
Switch.Contentto wrapLabelandDescriptionfor proper layout - 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.Contentfor label/description container