Back to Heroui

Switch

apps/docs/content/docs/en/react/migration/(components)/switch.mdx

3.2.49.0 KB
Original Source
<Callout type="info"> Refer to the [v3 Switch documentation](/docs/react/components/switch) for complete API reference, styling guide, and advanced examples. This guide only focuses on migrating from HeroUI v2. </Callout>

Structure Changes

In v2, Switch used a simple structure with children as label:

tsx
import { Switch } from "@heroui/react";

export default function App() {
  return <Switch>Enable notifications</Switch>;
}

In v3, Switch requires compound components:

tsx
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 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 - The clickable label wrapping the control and Label
  • Switch.Icon - For icons inside the thumb

Migration Examples

Controlled Switch

<Tabs items={["v2", "v3"]}> <Tab value="v2"> ```tsx import { useState } from "react";

const [isSelected, setIsSelected] = useState(true);

<Switch isSelected={isSelected} onValueChange={setIsSelected}>
  Airplane mode
</Switch>
```
</Tab> <Tab value="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>
```
</Tab> </Tabs>

Without Label

<Tabs items={["v2", "v3"]}> <Tab value="v2"> tsx <Switch defaultSelected aria-label="Automatic updates" /> </Tab> <Tab value="v3"> tsx <Switch defaultSelected aria-label="Automatic updates"> <Switch.Content> <Switch.Control> <Switch.Thumb /> </Switch.Control> </Switch.Content> </Switch> </Tab> </Tabs>

With Thumb Icon

<Tabs items={["v2", "v3"]}> <Tab value="v2"> tsx <Switch thumbIcon={<CheckIcon />}>Enable notifications</Switch> </Tab> <Tab value="v3"> tsx <Switch> <Switch.Content> <Switch.Control> <Switch.Thumb> <Switch.Icon> <CheckIcon /> </Switch.Icon> </Switch.Thumb> </Switch.Control> Enable notifications </Switch.Content> </Switch> </Tab> </Tabs>

With Start/End Content

<Tabs items={["v2", "v3"]}> <Tab value="v2"> tsx <Switch startContent={<SunIcon />} endContent={<MoonIcon />} > Dark mode </Switch> </Tab> <Tab value="v3"> tsx <Switch> <Switch.Content> <Switch.Control className="flex items-center gap-2"> <SunIcon /> <Switch.Thumb /> <MoonIcon /> </Switch.Control> Dark mode </Switch.Content> </Switch> </Tab> </Tabs>

With Label and Description

<Tabs items={["v2", "v3"]}> <Tab value="v2"> tsx <Switch description="You will receive notifications for all activity"> Enable notifications </Switch> </Tab> <Tab value="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>
```
</Tab> </Tabs>

Sizes and Colors

<Tabs items={["v2", "v3"]}> <Tab value="v2"> tsx <div className="flex gap-4"> <Switch size="sm">Small</Switch> <Switch size="md">Medium</Switch> <Switch size="lg">Large</Switch> </div> <Switch color="primary">Primary</Switch> <Switch color="success">Success</Switch> <Switch color="danger">Danger</Switch> </Tab> <Tab value="v3"> tsx <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> <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> </Tab> </Tabs>

Switch Group

<Tabs items={["v2", "v3"]}> <Tab value="v2"> tsx <div className="flex flex-col gap-2"> <Switch name="notifications">Allow Notifications</Switch> <Switch name="marketing">Marketing emails</Switch> </div> </Tab> <Tab value="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>
```
</Tab> </Tabs>

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: onValueChange prop
  • v3: onChange prop (same signature: (isSelected: boolean) => void)

Label Handling

  • v2: Children were used as label
  • v3: Label goes inside Switch.Content (the clickable label); Description/FieldError are siblings of Switch.Content

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.Content, Switch.Control, Switch.Thumb)
  2. Clickable Label: Use Switch.Content to wrap Switch.Control and Label; place Description/FieldError as siblings of Switch.Content
  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 as the clickable label wrapping the control and Label