Listbox
Migration guide for Listbox (renamed to ListBox with a capital "B") from HeroUI v2 to v3
Refer to the v3 ListBox documentation for complete API reference, styling guide, and advanced examples. This guide only focuses on migrating from HeroUI v2.
Overview
The Listbox component in HeroUI v3 has been renamed to ListBox and redesigned with a compound component pattern, requiring explicit structure with ListBox.Item, ListBox.Section, and their subcomponents.
Structure Changes
v2: Separate Components
In v2, Listbox used separate components:
import { Listbox, ListboxItem, ListboxSection } from "@heroui/react";
<Listbox>
<ListboxItem key="1">Item 1</ListboxItem>
</Listbox>v3: Compound Components
In v3, ListBox uses compound components:
import { ListBox, Label } from "@heroui/react";
<ListBox>
<ListBox.Item id="1" textValue="Item 1">
<Label>Item 1</Label>
</ListBox.Item>
</ListBox>Key Changes
1. Component Naming
v2: Listbox, ListboxItem, ListboxSection
v3: ListBox, ListBox.Item, ListBox.Section
2. Prop Changes
| v2 Prop | v3 Prop | Notes |
|---|---|---|
key | id | Renamed (required) |
| - | textValue | New required prop for accessibility |
variant | - | Removed (use Tailwind CSS) |
color | - | Removed (use Tailwind CSS) |
startContent | - | Removed (place icons manually) |
endContent | - | Removed (place icons manually) |
description | - | Removed (use Description component) |
title | - | Removed (use Header component) |
topContent | - | Removed |
bottomContent | - | Removed |
itemClasses | - | Use className props |
classNames | - | Use className props |
hideSelectedIcon | - | Omit ListBox.ItemIndicator instead |
disableAnimation | - | Removed |
isVirtualized | - | Removed |
virtualization | - | Removed |
selectedKeys | selectedKeys | Now uses Selection type (Set) |
3. Removed Props
The following props are no longer available in v3:
variant- Use Tailwind CSS classescolor- Use Tailwind CSS classesstartContent- Place icons manually in item contentendContent- Place icons manually in item contentdescription- UseDescriptioncomponenttitle(on Section) - UseHeadercomponenttopContent- Handle separatelybottomContent- Handle separatelyitemClasses- UseclassNameprops on itemsclassNames- UseclassNamepropshideSelectedIcon- OmitListBox.ItemIndicatorinsteaddisableAnimation- Animations handled differentlyisVirtualized- Virtualization removedvirtualization- Virtualization removed
Migration Examples
Basic Usage
import { Listbox, ListboxItem } from "@heroui/react";
export default function App() {
return (
<Listbox aria-label="Actions" onAction={(key) => alert(key)}>
<ListboxItem key="new">New file</ListboxItem>
<ListboxItem key="copy">Copy link</ListboxItem>
<ListboxItem key="edit">Edit file</ListboxItem>
</Listbox>
);
}import { Label, ListBox } from "@heroui/react";
export default function App() {
return (
<ListBox
aria-label="Actions"
selectionMode="none"
onAction={(key) => alert(key)}
>
<ListBox.Item id="new" textValue="New file">
<Label>New file</Label>
</ListBox.Item>
<ListBox.Item id="copy" textValue="Copy link">
<Label>Copy link</Label>
</ListBox.Item>
<ListBox.Item id="edit" textValue="Edit file">
<Label>Edit file</Label>
</ListBox.Item>
</ListBox>
);
}Single Selection
import { useState } from "react";
const [selectedKeys, setSelectedKeys] = useState(new Set(["text"]));
<Listbox
selectedKeys={selectedKeys}
selectionMode="single"
onSelectionChange={setSelectedKeys}
>
<ListboxItem key="text">Text</ListboxItem>
<ListboxItem key="number">Number</ListboxItem>
</Listbox>import { useState } from "react";
import type { Selection } from "@heroui/react";
const [selected, setSelected] = useState<Selection>(new Set(["text"]));
<ListBox
selectedKeys={selected}
selectionMode="single"
onSelectionChange={setSelected}
>
<ListBox.Item id="text" textValue="Text">
<Label>Text</Label>
<ListBox.ItemIndicator />
</ListBox.Item>
<ListBox.Item id="number" textValue="Number">
<Label>Number</Label>
<ListBox.ItemIndicator />
</ListBox.Item>
</ListBox>Multiple Selection
import { useState } from "react";
const [selectedKeys, setSelectedKeys] = useState(new Set(["text"]));
<Listbox
selectedKeys={selectedKeys}
selectionMode="multiple"
onSelectionChange={setSelectedKeys}
>
<ListboxItem key="text">Text</ListboxItem>
<ListboxItem key="number">Number</ListboxItem>
</Listbox>import { useState } from "react";
import type { Selection } from "@heroui/react";
const [selected, setSelected] = useState<Selection>(new Set(["text"]));
<ListBox
selectedKeys={selected}
selectionMode="multiple"
onSelectionChange={setSelected}
>
<ListBox.Item id="text" textValue="Text">
<Label>Text</Label>
<ListBox.ItemIndicator />
</ListBox.Item>
<ListBox.Item id="number" textValue="Number">
<Label>Number</Label>
<ListBox.ItemIndicator />
</ListBox.Item>
</ListBox>With Description
<ListboxItem
key="new"
description="Create a new file"
>
New file
</ListboxItem>import { Description, Label } from "@heroui/react";
<ListBox.Item id="new" textValue="New file">
<Label>New file</Label>
<Description>Create a new file</Description>
</ListBox.Item>With Icons
<ListboxItem
key="new"
startContent={<AddIcon />}
>
New file
</ListboxItem><ListBox.Item id="new" textValue="New file">
<AddIcon />
<Label>New file</Label>
</ListBox.Item>With Sections
<Listbox>
<ListboxSection title="Actions">
<ListboxItem key="new">New file</ListboxItem>
<ListboxItem key="edit">Edit file</ListboxItem>
</ListboxSection>
<ListboxSection title="Danger zone">
<ListboxItem key="delete">Delete</ListboxItem>
</ListboxSection>
</Listbox>import { Header, Label, Separator } from "@heroui/react";
<ListBox>
<ListBox.Section>
<Header>Actions</Header>
<ListBox.Item id="new" textValue="New file">
<Label>New file</Label>
</ListBox.Item>
<ListBox.Item id="edit" textValue="Edit file">
<Label>Edit file</Label>
</ListBox.Item>
</ListBox.Section>
<Separator />
<ListBox.Section>
<Header>Danger zone</Header>
<ListBox.Item id="delete" textValue="Delete" variant="danger">
<Label>Delete</Label>
</ListBox.Item>
</ListBox.Section>
</ListBox>With Custom Indicator
<ListboxItem
key="1"
selectedIcon={<CustomCheckIcon />}
>
Item 1
</ListboxItem><ListBox.Item id="1" textValue="Item 1">
<Label>Item 1</Label>
<ListBox.ItemIndicator>
{({isSelected}) =>
isSelected ? <CustomCheckIcon /> : null
}
</ListBox.ItemIndicator>
</ListBox.Item>Disabled Items
<Listbox disabledKeys={["disabled"]}>
<ListboxItem key="enabled">Enabled</ListboxItem>
<ListboxItem key="disabled">Disabled</ListboxItem>
</Listbox><ListBox disabledKeys={["disabled"]}>
<ListBox.Item id="enabled" textValue="Enabled">
<Label>Enabled</Label>
</ListBox.Item>
<ListBox.Item id="disabled" textValue="Disabled" isDisabled>
<Label>Disabled</Label>
</ListBox.Item>
</ListBox>Variants and Colors
<Listbox variant="flat" color="primary">
<ListboxItem key="1" color="danger">
Item 1
</ListboxItem>
</Listbox><ListBox className="bg-surface">
<ListBox.Item
id="1"
textValue="Item 1"
variant="danger"
className="text-danger"
>
<Label>Item 1</Label>
</ListBox.Item>
</ListBox>Component Anatomy
The v3 ListBox follows this structure:
ListBox (Root)
├── ListBox.Item
│ ├── Icon (optional, manual placement)
│ ├── Label (required)
│ ├── Description (optional)
│ └── ListBox.ItemIndicator (optional)
└── ListBox.Section (optional)
├── Header (optional)
└── ListBox.ItemBreaking Changes Summary
- Component Naming:
Listbox→ListBox,ListboxItem→ListBox.Item,ListboxSection→ListBox.Section - key → id: Prop renamed,
textValuenow required - Item Structure: Must use
Label,Description,ListBox.ItemIndicatorcomponents - Icons: Manual placement instead of
startContent/endContentprops - Sections: Use
Headercomponent instead oftitleprop - Styling Props Removed:
variant,color- use Tailwind CSS - Content Props Removed:
topContent,bottomContent- handle separately - Virtualization Removed:
isVirtualizedandvirtualizationprops removed - Selection Type: Uses
Selectiontype (Set) instead of arrays
Tips for Migration
- Update imports: Change
ListboxtoListBox, use compound components - Replace key prop: Change
keytoidand addtextValueprop - Add Label: Wrap item content in
Labelcomponent - Add Description: Use
Descriptioncomponent instead ofdescriptionprop - Add Indicator: Include
ListBox.ItemIndicatorfor selection indicators - Manual icons: Place icons directly in item content instead of
startContent/endContent - Sections: Use
Headercomponent instead oftitleprop - Styling: Use Tailwind CSS classes for variants and colors
- Selection: Ensure
selectedKeysusesSelectiontype (Set)
Need Help?
For v3 ListBox features and API:
- See the API Reference
- Check interactive examples
For community support: