Autocomplete
Migration guide for Autocomplete (renamed to ComboBox) from HeroUI v2 to v3
Refer to the v3 ComboBox documentation for complete API reference, styling guide, and advanced examples. This guide only focuses on migrating from HeroUI v2.
Overview
The Autocomplete component has been renamed to ComboBox in HeroUI v3 and redesigned with a compound component pattern, requiring explicit structure with ComboBox.InputGroup, ComboBox.Trigger, ComboBox.Popover, and ListBox components.
Structure Changes
v2: Single Component with Internal Structure
In v2, Autocomplete was a single component that wrapped Input internally:
import { Autocomplete, AutocompleteItem } from "@heroui/react";
<Autocomplete label="Select an animal">
<AutocompleteItem key="cat">Cat</AutocompleteItem>
<AutocompleteItem key="dog">Dog</AutocompleteItem>
</Autocomplete>v3: Compound Component Pattern
In v3, ComboBox uses compound components and requires explicit Input:
import { ComboBox, Input, Label, ListBox } from "@heroui/react";
<ComboBox>
<Label>Select an animal</Label>
<ComboBox.InputGroup>
<Input placeholder="Search animals..." />
<ComboBox.Trigger />
</ComboBox.InputGroup>
<ComboBox.Popover>
<ListBox>
<ListBox.Item id="cat" textValue="Cat">
Cat
<ListBox.ItemIndicator />
</ListBox.Item>
<ListBox.Item id="dog" textValue="Dog">
Dog
<ListBox.ItemIndicator />
</ListBox.Item>
</ListBox>
</ComboBox.Popover>
</ComboBox>Key Changes
1. Component Rename
v2: Autocomplete
v3: ComboBox
2. Component Structure
v2: Single component with internal Input
v3: Compound components (ComboBox.InputGroup, ComboBox.Trigger, ComboBox.Popover)
3. Item Components
v2: AutocompleteItem, AutocompleteSection
v3: ListBox.Item, ListBox.Section (from ListBox component)
4. Prop Changes
| v2 Prop | v3 Prop | Notes |
|---|---|---|
key (on AutocompleteItem) | id (on ListBox.Item) | Changed prop name |
| - | textValue (on ListBox.Item) | Now required for accessibility |
label | Label component | Separate component |
description | Description component | Separate component |
placeholder | placeholder (on Input) | Moved to Input component |
variant | - | Removed (use Tailwind CSS) |
color | - | Removed (use Tailwind CSS) |
size | - | Removed (use Tailwind CSS) |
radius | - | Removed (use Tailwind CSS) |
labelPlacement | - | Removed (use Label component positioning) |
startContent | - | Removed (add to Input directly) |
endContent | - | Removed (add to Input directly) |
selectorIcon | - | Removed (customize ComboBox.Trigger) |
clearIcon | - | Removed (not built-in) |
isClearable | - | Removed (implement manually) |
showScrollIndicators | - | Removed |
classNames | - | Use className props |
selectedKey | selectedKey | Still exists |
onSelectionChange | onSelectionChange | Still exists |
inputValue | inputValue | Still exists |
onInputChange | onInputChange | Still exists |
allowsCustomValue | allowsCustomValue | Still exists |
allowsEmptyCollection | allowsEmptyCollection | Still exists |
defaultFilter | defaultFilter | Still exists |
disabledKeys | disabledKeys | Still exists |
isDisabled | isDisabled | Still exists |
isRequired | isRequired | Still exists |
isInvalid | isInvalid | Still exists |
name | name | Still exists |
5. Removed Props
The following props are no longer available in v3:
variant,color,size,radius- Use Tailwind CSS classeslabelPlacement- Use Label component positioningstartContent,endContent- Add directly to Input componentselectorIcon,clearIcon- Customize ComboBox.Trigger or implement manuallyisClearable- Implement clear functionality manuallyshowScrollIndicators- Not supportedclassNames- UseclassNameprops on individual componentspopoverProps,listboxProps,inputProps- Configure components directlyscrollShadowProps- Not supportedselectorButtonProps,clearButtonProps- Not applicabledisableSelectorIconRotation- Not applicablemenuTrigger- Handled automaticallyisReadOnly- Use InputreadOnlypropfullWidth- Use Tailwind CSS classesisVirtualized,maxListboxHeight,itemHeight- Not supportedscrollRef- Not supportedonClose,onClear- Use different event handlersvalidationBehavior,validate- Use Form component
Migration Examples
Basic Usage
import { Autocomplete, AutocompleteItem } from "@heroui/react";
export default function App() {
return (
<Autocomplete className="max-w-xs" label="Select an animal">
<AutocompleteItem key="cat">Cat</AutocompleteItem>
<AutocompleteItem key="dog">Dog</AutocompleteItem>
<AutocompleteItem key="bird">Bird</AutocompleteItem>
</Autocomplete>
);
}import { ComboBox, Input, Label, ListBox } from "@heroui/react";
export default function App() {
return (
<ComboBox className="max-w-xs">
<Label>Select an animal</Label>
<ComboBox.InputGroup>
<Input placeholder="Search animals..." />
<ComboBox.Trigger />
</ComboBox.InputGroup>
<ComboBox.Popover>
<ListBox>
<ListBox.Item id="cat" textValue="Cat">
Cat
<ListBox.ItemIndicator />
</ListBox.Item>
<ListBox.Item id="dog" textValue="Dog">
Dog
<ListBox.ItemIndicator />
</ListBox.Item>
<ListBox.Item id="bird" textValue="Bird">
Bird
<ListBox.ItemIndicator />
</ListBox.Item>
</ListBox>
</ComboBox.Popover>
</ComboBox>
);
}With Description
<Autocomplete
label="Select an animal"
description="Choose your favorite animal"
>
<AutocompleteItem key="cat">Cat</AutocompleteItem>
</Autocomplete>import { Description } from "@heroui/react";
<ComboBox>
<Label>Select an animal</Label>
<ComboBox.InputGroup>
<Input placeholder="Search animals..." />
<ComboBox.Trigger />
</ComboBox.InputGroup>
<Description>Choose your favorite animal</Description>
<ComboBox.Popover>
<ListBox>
<ListBox.Item id="cat" textValue="Cat">
Cat
<ListBox.ItemIndicator />
</ListBox.Item>
</ListBox>
</ComboBox.Popover>
</ComboBox>Controlled Selection
import { useState } from "react";
const [selectedKey, setSelectedKey] = useState("cat");
<Autocomplete
selectedKey={selectedKey}
onSelectionChange={setSelectedKey}
label="Animal"
>
<AutocompleteItem key="cat">Cat</AutocompleteItem>
<AutocompleteItem key="dog">Dog</AutocompleteItem>
</Autocomplete>import { useState } from "react";
import type { Key } from "@heroui/react";
const [selectedKey, setSelectedKey] = useState<Key | null>("cat");
<ComboBox
selectedKey={selectedKey}
onSelectionChange={setSelectedKey}
>
<Label>Animal</Label>
<ComboBox.InputGroup>
<Input placeholder="Search animals..." />
<ComboBox.Trigger />
</ComboBox.InputGroup>
<ComboBox.Popover>
<ListBox>
<ListBox.Item id="cat" textValue="Cat">
Cat
<ListBox.ItemIndicator />
</ListBox.Item>
<ListBox.Item id="dog" textValue="Dog">
Dog
<ListBox.ItemIndicator />
</ListBox.Item>
</ListBox>
</ComboBox.Popover>
</ComboBox>With Sections
<Autocomplete label="Country">
<AutocompleteSection title="North America">
<AutocompleteItem key="usa">United States</AutocompleteItem>
<AutocompleteItem key="canada">Canada</AutocompleteItem>
</AutocompleteSection>
<AutocompleteSection title="Europe">
<AutocompleteItem key="uk">United Kingdom</AutocompleteItem>
</AutocompleteSection>
</Autocomplete>import { Header, Separator } from "@heroui/react";
<ComboBox>
<Label>Country</Label>
<ComboBox.InputGroup>
<Input placeholder="Search countries..." />
<ComboBox.Trigger />
</ComboBox.InputGroup>
<ComboBox.Popover>
<ListBox>
<ListBox.Section>
<Header>North America</Header>
<ListBox.Item id="usa" textValue="United States">
United States
<ListBox.ItemIndicator />
</ListBox.Item>
<ListBox.Item id="canada" textValue="Canada">
Canada
<ListBox.ItemIndicator />
</ListBox.Item>
</ListBox.Section>
<Separator />
<ListBox.Section>
<Header>Europe</Header>
<ListBox.Item id="uk" textValue="United Kingdom">
United Kingdom
<ListBox.ItemIndicator />
</ListBox.Item>
</ListBox.Section>
</ListBox>
</ComboBox.Popover>
</ComboBox>With Dynamic Items
const animals = [
{label: "Cat", key: "cat"},
{label: "Dog", key: "dog"}
];
<Autocomplete defaultItems={animals} label="Animal">
{(item) => (
<AutocompleteItem key={item.key}>
{item.label}
</AutocompleteItem>
)}
</Autocomplete>const animals = [
{id: "cat", name: "Cat"},
{id: "dog", name: "Dog"}
];
<ComboBox items={animals}>
<Label>Animal</Label>
<ComboBox.InputGroup>
<Input placeholder="Search animals..." />
<ComboBox.Trigger />
</ComboBox.InputGroup>
<ComboBox.Popover>
<ListBox>
{(item) => (
<ListBox.Item id={item.id} textValue={item.name}>
{item.name}
<ListBox.ItemIndicator />
</ListBox.Item>
)}
</ListBox>
</ComboBox.Popover>
</ComboBox>With Custom Filtering
<Autocomplete
label="Animal"
defaultFilter={(text, inputValue) => {
if (!inputValue) return true;
return text.toLowerCase().includes(inputValue.toLowerCase());
}}
>
<AutocompleteItem key="cat">Cat</AutocompleteItem>
</Autocomplete><ComboBox
defaultFilter={(text, inputValue) => {
if (!inputValue) return true;
return text.toLowerCase().includes(inputValue.toLowerCase());
}}
>
<Label>Animal</Label>
<ComboBox.InputGroup>
<Input placeholder="Search animals..." />
<ComboBox.Trigger />
</ComboBox.InputGroup>
<ComboBox.Popover>
<ListBox>
<ListBox.Item id="cat" textValue="Cat">
Cat
<ListBox.ItemIndicator />
</ListBox.Item>
</ListBox>
</ComboBox.Popover>
</ComboBox>With Disabled Items
<Autocomplete
label="Animal"
disabledKeys={["dog"]}
>
<AutocompleteItem key="cat">Cat</AutocompleteItem>
<AutocompleteItem key="dog">Dog</AutocompleteItem>
</Autocomplete><ComboBox disabledKeys={["dog"]}>
<Label>Animal</Label>
<ComboBox.InputGroup>
<Input placeholder="Search animals..." />
<ComboBox.Trigger />
</ComboBox.InputGroup>
<ComboBox.Popover>
<ListBox>
<ListBox.Item id="cat" textValue="Cat">
Cat
<ListBox.ItemIndicator />
</ListBox.Item>
<ListBox.Item id="dog" textValue="Dog">
Dog
<ListBox.ItemIndicator />
</ListBox.Item>
</ListBox>
</ComboBox.Popover>
</ComboBox>Required Field
<Autocomplete
label="Animal"
isRequired
>
<AutocompleteItem key="cat">Cat</AutocompleteItem>
</Autocomplete>import { FieldError, Form } from "@heroui/react";
<Form>
<ComboBox isRequired name="animal">
<Label>Animal</Label>
<ComboBox.InputGroup>
<Input placeholder="Search animals..." />
<ComboBox.Trigger />
</ComboBox.InputGroup>
<ComboBox.Popover>
<ListBox>
<ListBox.Item id="cat" textValue="Cat">
Cat
<ListBox.ItemIndicator />
</ListBox.Item>
</ListBox>
</ComboBox.Popover>
<FieldError />
</ComboBox>
</Form>With Error Message
<Autocomplete
label="Animal"
isInvalid
errorMessage="Please select an animal"
>
<AutocompleteItem key="cat">Cat</AutocompleteItem>
</Autocomplete>import { FieldError } from "@heroui/react";
<ComboBox isInvalid>
<Label>Animal</Label>
<ComboBox.InputGroup>
<Input placeholder="Search animals..." />
<ComboBox.Trigger />
</ComboBox.InputGroup>
<ComboBox.Popover>
<ListBox>
<ListBox.Item id="cat" textValue="Cat">
Cat
<ListBox.ItemIndicator />
</ListBox.Item>
</ListBox>
</ComboBox.Popover>
<FieldError>Please select an animal</FieldError>
</ComboBox>Custom Styling
<Autocomplete
label="Animal"
variant="bordered"
color="primary"
size="lg"
classNames={{
base: "custom-base",
listbox: "custom-listbox"
}}
>
<AutocompleteItem key="cat">Cat</AutocompleteItem>
</Autocomplete><ComboBox className="custom-combobox">
<Label>Animal</Label>
<ComboBox.InputGroup className="custom-input-group">
<Input placeholder="Search animals..." className="custom-input" />
<ComboBox.Trigger className="custom-trigger" />
</ComboBox.InputGroup>
<ComboBox.Popover className="custom-popover">
<ListBox className="custom-listbox">
<ListBox.Item id="cat" textValue="Cat" className="custom-item">
Cat
<ListBox.ItemIndicator />
</ListBox.Item>
</ListBox>
</ComboBox.Popover>
</ComboBox>Component Anatomy
The v3 ComboBox follows this structure:
ComboBox (Root)
├── Label
├── ComboBox.InputGroup
│ ├── Input
│ └── ComboBox.Trigger
├── Description (optional)
├── ComboBox.Popover
│ └── ListBox
│ ├── ListBox.Item
│ │ ├── [Content]
│ │ └── ListBox.ItemIndicator (optional)
│ └── ListBox.Section (optional)
│ ├── Header
│ └── ListBox.Item
└── FieldError (optional)Important Notes
Component Rename
- v2:
Autocomplete→ v3:ComboBox - Update all imports and component references
Item Components
- v2:
AutocompleteItem,AutocompleteSection - v3:
ListBox.Item,ListBox.Section(from ListBox component)
Item Props
- v2: Used
keyprop onAutocompleteItem - v3: Use
idprop onListBox.Item(required) andtextValueprop (required)
Input Component
- v2: Input was internal to Autocomplete
- v3: Must explicitly include
Inputcomponent insideComboBox.InputGroup
Label and Description
- v2: Props on Autocomplete component
- v3: Separate
LabelandDescriptioncomponents
Selection Indicators
- v2: Automatic selection indicators
- v3: Must explicitly include
ListBox.ItemIndicatorcomponent in items
Clear Button
- v2: Built-in clear button with
isClearableprop - v3: Not built-in - implement manually if needed
Styling
- v2: Many styling props (
variant,color,size,radius) - v3: Use Tailwind CSS classes directly
Breaking Changes Summary
- Component Rename:
Autocomplete→ComboBox - Component Structure: Single component → Compound components
- Item Components:
AutocompleteItem→ListBox.Item - Item Props:
key→id+textValue(required) - Input: Internal → Explicit
Inputcomponent required - Label/Description: Props → Separate components
- Styling Props Removed:
variant,color,size,radius- use Tailwind CSS - Clear Button: Built-in → Manual implementation required
- ClassNames Removed: Use
classNameprops on individual components - Many Props Removed: See prop changes table above
Tips for Migration
- Rename component: Change
AutocompletetoComboBox - Update imports: Import
ComboBox,Input,Label,ListBoxfrom@heroui/react - Restructure: Use compound component pattern with
ComboBox.InputGroup,ComboBox.Trigger,ComboBox.Popover - Add Input: Include explicit
Inputcomponent - Update items: Change
AutocompleteItemtoListBox.Item - Add textValue: Add
textValueprop to all items (required) - Update keys: Change
keyprop toidprop - Add indicators: Include
ListBox.ItemIndicatorfor selection indicators - Update labels: Use
Labelcomponent instead oflabelprop - Update descriptions: Use
Descriptioncomponent instead ofdescriptionprop - Update styling: Replace styling props with Tailwind CSS classes
- Handle clear: Implement clear button manually if needed
Need Help?
For v3 ComboBox features and API:
- See the API Reference
- Check interactive examples
For community support: