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

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 Propv3 LocationNotes
key (on Tab)id (on Tab and Panel)Changed prop name
title (on Tab)Content goes directly in Tabs.Tab
isVerticalorientationChanged to "horizontal" | "vertical"
placementUse orientation and layout
variantvariantSimplified to primary | secondary only
colorRemoved (use Tailwind CSS)
sizeRemoved (use Tailwind CSS)
radiusRemoved (use Tailwind CSS)
classNamesUse className props on individual components
disableCursorAnimationUse Tabs.Indicator component
disableAnimationRemoved (animations handled differently)
fullWidthRemoved (use Tailwind CSS)

3. Component Changes

  • Tab identification: keyid (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

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

  1. Component Structure: Must use compound components (Tabs.ListContainer, Tabs.List, Tabs.Tab, Tabs.Indicator, Tabs.Separator, Tabs.Panel)
  2. Tab Identification: keyid (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: isVerticalorientation 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)

On this page