Tabs
Migration guide for Tabs from HeroUI v2 to v3
Refer to the v3 Tabs documentation for complete API reference, styling guide, and advanced examples. This guide only focuses on migrating from HeroUI v2.
Structure Changes
In v2, Tabs used Tab component with title prop and children as panel content:
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:
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 betweenTabs.TabandTabs.Panel) - Tab content:
titleprop → direct children inTabs.Tab - Panel content: Tab children → separate
Tabs.Panelcomponent - Indicator: Automatic cursor → explicit
Tabs.Indicatorcomponent - Separator: New
Tabs.Separatorcomponent to display separator lines between tabs
Migration Examples
Controlled Tabs
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>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>With Icons
<Tabs aria-label="Options">
<Tab key="photos" title={<><PhotoIcon /> Photos</>}>
Content
</Tab>
</Tabs><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>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.
<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
- Component Structure: Must use compound components (
Tabs.ListContainer,Tabs.List,Tabs.Tab,Tabs.Indicator,Tabs.Separator,Tabs.Panel) - Tab Identification:
key→id(must match between tab and panel) - Tab Content:
titleprop removed - content goes directly inTabs.Tab - Panel Separation: Panel content moved to separate
Tabs.Panelcomponent - Indicator: Must explicitly include
Tabs.Indicatorin each tab - Orientation:
isVertical→orientationprop - Styling:
variantsimplified toprimary|secondary;color,size,radius,placementremoved - use Tailwind for more - ClassNames Removed: Use
classNameprops on individual components - Separator (New): Use
Tabs.SeparatorinsideTabs.Tabto display separator lines between tabs (no v2 equivalent)