Pro--% off in--d : --h : --m : --s
HeroUI

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 Propv3 LocationNotes
onValueChangeonChangeRenamed event handler
sizesizeStill exists on root (sm | md | lg)
labelUse Label component
colorRemoved (use Tailwind CSS)
thumbIconUse Switch.Icon inside Switch.Thumb
startContentCustomize control directly
endContentCustomize control directly
classNamesUse className props on individual components
disableAnimationRemoved (animations handled differently)

3. New Components

  • SwitchGroup - For grouping multiple switches
  • Switch.Content - Container for label and description
  • Switch.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: onValueChange prop
  • v3: onChange prop (same signature: (isSelected: boolean) => void)

Label Handling

  • v2: Children were used as label
  • v3: Use Label component inside Switch.Content; optionally add Description alongside it

Icons

  • v2: thumbIcon prop for icon inside thumb, startContent/endContent for icons outside
  • v3: Use Switch.Icon inside Switch.Thumb for thumb icon, customize Switch.Control for start/end content

Summary

  1. Component Structure: Must use compound components (Switch.Control, Switch.Thumb, Switch.Content)
  2. Content Container: Use Switch.Content to wrap Label and Description for proper layout
  3. Label Handling: Children no longer used as label - use Label component inside Switch.Content
  4. Event Handler: onValueChangeonChange
  5. Styling Props Removed: color - use Tailwind CSS
  6. Icon Props Removed: thumbIcon, startContent, endContent - use components or customize directly
  7. ClassNames Removed: Use className props on individual components
  8. New Components: SwitchGroup for grouping switches, Switch.Content for label/description container

On this page