ProComponents, templates & AI tooling
HeroUI
27.7k

Autocomplete

Autocomplete 从 HeroUI v2 到 v3 的迁移指南。

在 v3 中,v2 的 Autocomplete 可以迁移为 v3 Autocompletev3 ComboBox,取决于你的使用场景。请参阅下文「何时使用 Autocomplete 与 ComboBox」。本指南只关注从 HeroUI v2 的迁移。

何时使用 Autocomplete 与 ComboBox

v3 提供两个组件来替代 v2 的 Autocomplete:

组件适用场景输入方式底层实现
Autocomplete选择器式交互,Popover 内带搜索 / 筛选字段按钮触发器展示已选值;Popover 内为搜索输入React Aria Select + Autocomplete
ComboBox在可见输入框中输入以筛选下拉列表内联文本输入与下拉触发器React Aria ComboBox

使用 Autocomplete:用户从预定义列表中选择,且搜索字段应出现在下拉内(类似可搜索的选择器)。

使用 ComboBox:用户在可见输入框中直接输入以筛选或搜索选项(行为最接近 v2)。

结构变化

在 v2 中,Autocomplete 是内部包装 Input 的单一组件:

import { Autocomplete, AutocompleteItem } from "@heroui/react";

export default function App() {
  return (
    <Autocomplete label="Select an animal">
      <AutocompleteItem key="cat">Cat</AutocompleteItem>
      <AutocompleteItem key="dog">Dog</AutocompleteItem>
    </Autocomplete>
  );
}

迁移到 v3 ComboBox(最接近 v2)

ComboBox 提供与 v2 Autocomplete 最接近的体验:内联文本输入并随输入筛选选项。

import { ComboBox, Input, Label, ListBox } from "@heroui/react";

export default function App() {
  return (
    <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>
  );
}

迁移到 v3 Autocomplete(可搜索的选择器)

Autocomplete 提供选择器式触发器,并在 Popover 内提供搜索 / 筛选字段:

import { Autocomplete, Label, SearchField, ListBox, useFilter } from "@heroui/react";

export default function App() {
  const { contains } = useFilter({ sensitivity: "base" });

  return (
    <Autocomplete>
      <Label>Select an animal</Label>
      <Autocomplete.Trigger>
        <Autocomplete.Value />
        <Autocomplete.ClearButton />
        <Autocomplete.Indicator />
      </Autocomplete.Trigger>
      <Autocomplete.Popover>
        <Autocomplete.Filter filter={contains}>
          <SearchField>
            <SearchField.Group>
              <SearchField.SearchIcon />
              <SearchField.Input placeholder="Search..." />
            </SearchField.Group>
          </SearchField>
          <ListBox>
            <ListBox.Item id="cat" textValue="Cat">
              Cat
              <ListBox.ItemIndicator />
            </ListBox.Item>
            <ListBox.Item id="dog" textValue="Dog">
              Dog
              <ListBox.ItemIndicator />
            </ListBox.Item>
          </ListBox>
        </Autocomplete.Filter>
      </Autocomplete.Popover>
    </Autocomplete>
  );
}

关键变化

1. 两个替代组件

v2: Autocomplete(单一组件)
v3: ComboBox(内联输入 + 下拉)或 Autocomplete(选择器式 + Popover 内搜索)

2. 组件结构

v2: 单一组件,内部包含 Input
v3 ComboBox: 复合组件(ComboBox.InputGroupComboBox.TriggerComboBox.Popover
v3 Autocomplete: 复合组件(Autocomplete.TriggerAutocomplete.ValueAutocomplete.ClearButtonAutocomplete.IndicatorAutocomplete.PopoverAutocomplete.Filter

3. 菜单项组件

v2: AutocompleteItemAutocompleteSection
v3: ListBox.ItemListBox.Section(来自 ListBox)

4. 菜单项标识

v2: React 的 key 同时用于列表协调与选择时的项标识。
v3:ListBox.Item 上使用 idtextValue(状态与无障碍);列表中的项仍保留 React 的 key

5. Autocomplete 专用子组件(v3)

v3 Autocomplete 引入 v2 中不存在的子组件:

子组件用途
Autocomplete.Trigger打开 Popover 的按钮组
Autocomplete.Value显示当前选中值或占位符
Autocomplete.ClearButton清除当前选择
Autocomplete.Indicator下拉箭头图标(打开时旋转)
Autocomplete.Popover下拉 Popover 容器
Autocomplete.Filter包裹 SearchFieldListBox 以启用筛选;接受 filter 函数、inputValueonInputChange

6. SearchField 集成

v3 Autocomplete 在 Autocomplete.Filter 内使用 SearchField,作为 Popover 中的搜索输入:

<Autocomplete.Filter filter={contains}>
  <SearchField>
    <SearchField.Group>
      <SearchField.SearchIcon />
      <SearchField.Input placeholder="Search..." />
    </SearchField.Group>
  </SearchField>
  <ListBox>...</ListBox>
</Autocomplete.Filter>

SearchField 还有子组件:SearchField.GroupSearchField.InputSearchField.SearchIconSearchField.ClearButton

7. useFilter Hook

v3 Autocomplete 使用 useFilter hook(来自 React Aria,由 @heroui/react 再导出)提供带区域设置感知的筛选函数:

import { useFilter } from "@heroui/react";

const { contains } = useFilter({ sensitivity: "base" });

// 传给 Autocomplete.Filter
<Autocomplete.Filter filter={contains}>
  ...
</Autocomplete.Filter>

该 hook 返回 containsstartsWithendsWithsensitivity 控制区域设置感知匹配("base""accent""case""variant")。

8. Prop 变更(ComboBox)

v2 propv3 位置说明
id(在 ListBox.Item 上)状态用的项标识
textValue(在 ListBox.Item 上)无障碍(提前输入)
labelLabel使用 Label 组件
descriptionDescription使用 Description 组件
placeholderInput写在 Inputplaceholder
selectedKeyonSelectionChangeinputValueonInputChangeComboBox与 v2 相同
allowsCustomValueallowsEmptyCollectiondefaultFilterComboBox与 v2 相同
disabledKeysisDisabledisRequiredisInvalidnameComboBox与 v2 相同
menuTriggerComboBox"focus"(默认)、"input""manual"
variantcolorsizeradius已移除(请使用 Tailwind CSS)
labelPlacement已移除(请自行摆放 Label)
startContentendContent加到 Input 或 InputGroup
selectorIconclearIcon自定义 ComboBox.Trigger 或手动实现
isClearable手动实现
showScrollIndicators已移除
classNames在各部件上使用 className
popoverPropslistboxPropsinputProps直接在对应子组件上配置
scrollShadowPropsscrollRef已移除
selectorButtonPropsclearButtonPropsdisableSelectorIconRotation已移除
isReadOnlyComboBoxComboBox 上的 isReadOnly prop
fullWidthComboBoxComboBox 上的 fullWidth prop
isVirtualizedmaxListboxHeightitemHeight已移除
onCloseonClear改用其他事件处理函数
validationBehaviorvalidateComboBox写在 ComboBox 上的 prop

9. Prop 变更(Autocomplete)

v2 propv3 位置说明
id(在 ListBox.Item 上)状态用的项标识
textValue(在 ListBox.Item 上)无障碍(提前输入)
labelLabel使用 Label 组件
descriptionDescription使用 Description 组件
placeholderAutocomplete根组件上的 placeholder prop
selectedKey / onSelectionChangevalue / onChangeAutocomplete 上已重命名
selectionModeAutocomplete"single"(默认)或 "multiple"
inputValueonInputChangeAutocomplete.Filter写在 Filter 上的 inputValueonInputChange
disabledKeysisDisabledisRequiredisInvalidnameAutocomplete与 v2 相同
variantcolorsizeradius已移除(请使用 Tailwind CSS);variant 支持 "primary" / "secondary"
isClearableAutocomplete.ClearButton内置子组件
selectorIconAutocomplete.Indicator将自定义图标作为 children 传入
onClearAutocomplete根组件上的 onClear prop
fullWidthAutocomplete根组件上的 fullWidth prop
classNames在各部件上使用 className
popoverPropslistboxPropsinputProps直接在对应子组件上配置

迁移示例

受控选择(ComboBox)

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>

受控选择(Autocomplete)

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";
import { Autocomplete, Label, SearchField, ListBox, useFilter } from "@heroui/react";

const [value, setValue] = useState<Key | Key[] | null>("cat");
const { contains } = useFilter({ sensitivity: "base" });

<Autocomplete value={value} onChange={setValue}>
  <Label>Animal</Label>
  <Autocomplete.Trigger>
    <Autocomplete.Value />
    <Autocomplete.ClearButton />
    <Autocomplete.Indicator />
  </Autocomplete.Trigger>
  <Autocomplete.Popover>
    <Autocomplete.Filter filter={contains}>
      <SearchField>
        <SearchField.Group>
          <SearchField.SearchIcon />
          <SearchField.Input placeholder="Search..." />
        </SearchField.Group>
      </SearchField>
      <ListBox>
        <ListBox.Item id="cat" textValue="Cat">
          <Label>Cat</Label>
          <ListBox.ItemIndicator />
        </ListBox.Item>
        <ListBox.Item id="dog" textValue="Dog">
          <Label>Dog</Label>
          <ListBox.ItemIndicator />
        </ListBox.Item>
      </ListBox>
    </Autocomplete.Filter>
  </Autocomplete.Popover>
</Autocomplete>

带分组

<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>

使用 useFilter(Autocomplete)

{/* v2 在内部处理筛选 */}
<Autocomplete label="Animal">
  <AutocompleteItem key="cat">Cat</AutocompleteItem>
  <AutocompleteItem key="dog">Dog</AutocompleteItem>
</Autocomplete>
import { Autocomplete, Label, SearchField, ListBox, useFilter } from "@heroui/react";

function FilterExample() {
  const { contains } = useFilter({ sensitivity: "base" });

  return (
    <Autocomplete>
      <Label>Animal</Label>
      <Autocomplete.Trigger>
        <Autocomplete.Value />
        <Autocomplete.ClearButton />
        <Autocomplete.Indicator />
      </Autocomplete.Trigger>
      <Autocomplete.Popover>
        <Autocomplete.Filter filter={contains}>
          <SearchField>
            <SearchField.Group>
              <SearchField.SearchIcon />
              <SearchField.Input placeholder="Search..." />
            </SearchField.Group>
          </SearchField>
          <ListBox>
            <ListBox.Item id="cat" textValue="Cat">
              <Label>Cat</Label>
              <ListBox.ItemIndicator />
            </ListBox.Item>
            <ListBox.Item id="dog" textValue="Dog">
              <Label>Dog</Label>
              <ListBox.ItemIndicator />
            </ListBox.Item>
          </ListBox>
        </Autocomplete.Filter>
      </Autocomplete.Popover>
    </Autocomplete>
  );
}

表单校验

{/* Required field */}
<Autocomplete label="Animal" isRequired>
  <AutocompleteItem key="cat">Cat</AutocompleteItem>
</Autocomplete>

{/* With error message */}
<Autocomplete
  label="Animal"
  isInvalid
  errorMessage="Please select an animal"
>
  <AutocompleteItem key="cat">Cat</AutocompleteItem>
</Autocomplete>
import { FieldError, Form } from "@heroui/react";

{/* Required field */}
<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 */}
<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>

组件剖析

ComboBox 剖析

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)

Autocomplete 剖析

Autocomplete (Root)
  ├── Label
  ├── Autocomplete.Trigger
  │   ├── Autocomplete.Value
  │   ├── Autocomplete.ClearButton
  │   └── Autocomplete.Indicator
  ├── Description (optional)
  ├── Autocomplete.Popover
  │   └── Autocomplete.Filter
  │       ├── SearchField
  │       │   └── SearchField.Group
  │       │       ├── SearchField.SearchIcon
  │       │       └── SearchField.Input
  │       └── ListBox
  │           ├── ListBox.Item
  │           │   ├── [Content]
  │           │   └── ListBox.ItemIndicator (optional)
  │           └── ListBox.Section (optional)
  │               ├── Header
  │               └── ListBox.Item
  └── FieldError (optional)

总结

  1. 两个替代组件:v2 Autocomplete 可迁移为 v3 ComboBox(内联输入)或 v3 Autocomplete(Popover 内可筛选的选择器)。
  2. 组件结构:由带 prop 的单一组件变为带显式子节点的复合组件。
  3. 菜单项组件AutocompleteItemListBox.ItemAutocompleteSectionListBox.Section
  4. 菜单项标识:在项上使用 idtextValue;列表协调仍用 React 的 key
  5. 输入:v3 ComboBox 需要显式 Input;v3 Autocomplete 在 Autocomplete.Filter 内使用 SearchField
  6. 标签 / 描述:对应 prop 拆为独立的 LabelDescription 组件。
  7. 筛选:v3 Autocomplete 通过 Autocomplete.FilteruseFilter 做区域设置感知筛选;v3 ComboBox 使用 defaultFilter prop。
  8. 清除按钮:v3 Autocomplete 内置 Autocomplete.ClearButton;v3 ComboBox 需手动实现。
  9. 选中值展示:v3 Autocomplete 用 Autocomplete.Value 展示选中值,并支持渲染 prop。
  10. 样式类 prop 已移除colorsizeradius 已移除(请使用 Tailwind CSS);variant 现支持 "primary" / "secondary"
  11. classNames 已移除:在各子组件上使用 className prop。
  12. useFilter Hook:v3 新增,提供 containsstartsWithendsWith 用于区域设置感知的文本匹配。

本页目录