---
title: Tabs
description: Migration guide for Tabs from HeroUI v2 to v3
---

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

## Structure Changes

In v2, Tabs used `Tab` component with `title` prop and children as panel content:

```tsx
import { Tabs, Tab } from "@heroui/react";

export default function App() {
  return (
    <Tabs aria-label="Options">
      <Tab key="photos" title="Photos">
        <Card>Content here</Card>
      </Tab>
    </Tabs>
  );
}
```

In v3, Tabs requires compound components with separate tab and panel:

```tsx
import { Tabs } from "@heroui/react";

export default function App() {
  return (
    <Tabs>
      <Tabs.ListContainer>
        <Tabs.List aria-label="Options">
          <Tabs.Tab id="photos">
            Photos
            <Tabs.Indicator />
          </Tabs.Tab>
        </Tabs.List>
      </Tabs.ListContainer>
      <Tabs.Panel id="photos">
        <Card>Content here</Card>
      </Tabs.Panel>
    </Tabs>
  );
}
```

## Key Changes

### 1. Component Structure

**v2:** `Tabs` with `Tab` children (title prop + children as panel)  
**v3:** Compound components (`Tabs.ListContainer`, `Tabs.List`, `Tabs.Tab`, `Tabs.Indicator`, `Tabs.Separator`, `Tabs.Panel`)

### 2. Prop Changes

| v2 Prop | v3 Location | Notes |
|---------|-------------|-------|
| `key` (on Tab) | `id` (on Tab and Panel) | Changed prop name |
| `title` (on Tab) | — | Content goes directly in `Tabs.Tab` |
| `isVertical` | `orientation` | Changed to `"horizontal"` \| `"vertical"` |
| `placement` | — | Use `orientation` and layout |
| `variant` | `variant` | Simplified to `primary` \| `secondary` only |
| `color` | — | Removed (use Tailwind CSS) |
| `size` | — | Removed (use Tailwind CSS) |
| `radius` | — | Removed (use Tailwind CSS) |
| `classNames` | — | Use `className` props on individual components |
| `disableCursorAnimation` | — | Use `Tabs.Indicator` component |
| `disableAnimation` | — | Removed (animations handled differently) |
| `fullWidth` | — | Removed (use Tailwind CSS) |

### 3. Component Changes

- **Tab identification**: `key` → `id` (must match between `Tabs.Tab` and `Tabs.Panel`)
- **Tab content**: `title` prop → direct children in `Tabs.Tab`
- **Panel content**: Tab children → separate `Tabs.Panel` component
- **Indicator**: Automatic cursor → explicit `Tabs.Indicator` component
- **Separator**: New `Tabs.Separator` component to display separator lines between tabs

## Migration Examples

### Controlled Tabs

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

    const [selected, setSelected] = useState("photos");

    <Tabs selectedKey={selected} onSelectionChange={setSelected}>
      <Tab key="photos" title="Photos">Content</Tab>
      <Tab key="music" title="Music">Content</Tab>
    </Tabs>
    ```
  </Tab>
  <Tab value="v3">
    ```tsx
    import { useState } from "react";

    const [selected, setSelected] = useState("photos");

    <Tabs selectedKey={selected} onSelectionChange={setSelected}>
      <Tabs.ListContainer>
        <Tabs.List aria-label="Options">
          <Tabs.Tab id="photos">
            Photos
            <Tabs.Indicator />
          </Tabs.Tab>
          <Tabs.Tab id="music">
            Music
            <Tabs.Indicator />
          </Tabs.Tab>
        </Tabs.List>
      </Tabs.ListContainer>
      <Tabs.Panel id="photos">Content</Tabs.Panel>
      <Tabs.Panel id="music">Content</Tabs.Panel>
    </Tabs>
    ```
  </Tab>
</Tabs>

### With Icons

<Tabs items={["v2", "v3"]}>
  <Tab value="v2">
    ```tsx
    <Tabs aria-label="Options">
      <Tab key="photos" title={<><PhotoIcon /> Photos</>}>
        Content
      </Tab>
    </Tabs>
    ```
  </Tab>
  <Tab value="v3">
    ```tsx
    <Tabs>
      <Tabs.ListContainer>
        <Tabs.List aria-label="Options">
          <Tabs.Tab id="photos">
            <PhotoIcon />
            Photos
            <Tabs.Indicator />
          </Tabs.Tab>
        </Tabs.List>
      </Tabs.ListContainer>
      <Tabs.Panel id="photos">Content</Tabs.Panel>
    </Tabs>
    ```
  </Tab>
</Tabs>

### With Separator

In v3, you can add `Tabs.Separator` inside each `Tabs.Tab` (except the first) to display separator lines between tabs. This is a new feature with no v2 equivalent.

```tsx
<Tabs>
  <Tabs.ListContainer>
    <Tabs.List aria-label="Options">
      <Tabs.Tab id="photos">
        Photos
        <Tabs.Indicator />
      </Tabs.Tab>
      <Tabs.Tab id="music">
        <Tabs.Separator />
        Music
        <Tabs.Indicator />
      </Tabs.Tab>
      <Tabs.Tab id="videos">
        <Tabs.Separator />
        Videos
        <Tabs.Indicator />
      </Tabs.Tab>
    </Tabs.List>
  </Tabs.ListContainer>
  <Tabs.Panel id="photos">Photos content</Tabs.Panel>
  <Tabs.Panel id="music">Music content</Tabs.Panel>
  <Tabs.Panel id="videos">Videos content</Tabs.Panel>
</Tabs>
```

## Component Anatomy

The v3 Tabs follows this structure:

```
Tabs (Root)
  ├── Tabs.ListContainer
  │   └── Tabs.List
  │       └── Tabs.Tab
  │           ├── Tabs.Separator (optional, omit on first tab)
  │           └── Tabs.Indicator (optional)
  └── Tabs.Panel (one per tab, matching id)
```

## Summary

1. **Component Structure**: Must use compound components (`Tabs.ListContainer`, `Tabs.List`, `Tabs.Tab`, `Tabs.Indicator`, `Tabs.Separator`, `Tabs.Panel`)
2. **Tab Identification**: `key` → `id` (must match between tab and panel)
3. **Tab Content**: `title` prop removed - content goes directly in `Tabs.Tab`
4. **Panel Separation**: Panel content moved to separate `Tabs.Panel` component
5. **Indicator**: Must explicitly include `Tabs.Indicator` in each tab
6. **Orientation**: `isVertical` → `orientation` prop
7. **Styling**: `variant` simplified to `primary` \| `secondary`; `color`, `size`, `radius`, `placement` removed - use Tailwind for more
8. **ClassNames Removed**: Use `className` props on individual components
9. **Separator (New)**: Use `Tabs.Separator` inside `Tabs.Tab` to display separator lines between tabs (no v2 equivalent)
