Autocomplete
Autocomplete 从 HeroUI v2 到 v3 的迁移指南。
在 v3 中,v2 的 Autocomplete 可以迁移为 v3 Autocomplete 或 v3 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 "@lenso/ui";
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 "@lenso/ui";
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 "@lenso/ui";
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.InputGroup、ComboBox.Trigger、ComboBox.Popover)
v3 Autocomplete: 复合组件(Autocomplete.Trigger、Autocomplete.Value、Autocomplete.ClearButton、Autocomplete.Indicator、Autocomplete.Popover、Autocomplete.Filter)
3. 菜单项组件
v2: AutocompleteItem、AutocompleteSection
v3: ListBox.Item、ListBox.Section(来自 ListBox)
4. 菜单项标识
v2: React 的 key 同时用于列表协调与选择时的项标识。
v3: 在 ListBox.Item 上使用 id 与 textValue(状态与无障碍);列表中的项仍保留 React 的 key。
5. Autocomplete 专用子组件(v3)
v3 Autocomplete 引入 v2 中不存在的子组件:
| 子组件 | 用途 |
|---|---|
Autocomplete.Trigger | 打开 Popover 的按钮组 |
Autocomplete.Value | 显示当前选中值或占位符 |
Autocomplete.ClearButton | 清除当前选择 |
Autocomplete.Indicator | 下拉箭头图标(打开时旋转) |
Autocomplete.Popover | 下拉 Popover 容器 |
Autocomplete.Filter | 包裹 SearchField 与 ListBox 以启用筛选;接受 filter 函数、inputValue、onInputChange |
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.Group、SearchField.Input、SearchField.SearchIcon、SearchField.ClearButton。
7. useFilter Hook
v3 Autocomplete 使用 useFilter hook(来自 React Aria,由 @lenso/ui 再导出)提供带区域设置感知的筛选函数:
import { useFilter } from "@lenso/ui";
const { contains } = useFilter({ sensitivity: "base" });
// 传给 Autocomplete.Filter<Autocomplete.Filter filter={contains}> ...</Autocomplete.Filter>该 hook 返回 contains、startsWith、endsWith。sensitivity 控制区域设置感知匹配("base"、"accent"、"case"、"variant")。
8. Prop 变更(ComboBox)
| v2 prop | v3 位置 | 说明 |
|---|---|---|
| — | id(在 ListBox.Item 上) | 状态用的项标识 |
| — | textValue(在 ListBox.Item 上) | 无障碍(提前输入) |
label | Label | 使用 Label 组件 |
description | Description | 使用 Description 组件 |
placeholder | Input | 写在 Input 的 placeholder |
selectedKey、onSelectionChange、inputValue、onInputChange | ComboBox | 与 v2 相同 |
allowsCustomValue、allowsEmptyCollection、defaultFilter | ComboBox | 与 v2 相同 |
disabledKeys、isDisabled、isRequired、isInvalid、name | ComboBox | 与 v2 相同 |
menuTrigger | ComboBox | "focus"(默认)、"input" 或 "manual" |
variant、color、size、radius | — | 已移除(请使用 Tailwind CSS) |
labelPlacement | — | 已移除(请自行摆放 Label) |
startContent、endContent | — | 加到 Input 或 InputGroup |
selectorIcon、clearIcon | — | 自定义 ComboBox.Trigger 或手动实现 |
isClearable | — | 手动实现 |
showScrollIndicators | — | 已移除 |
classNames | — | 在各部件上使用 className |
popoverProps、listboxProps、inputProps | — | 直接在对应子组件上配置 |
scrollShadowProps、scrollRef | — | 已移除 |
selectorButtonProps、clearButtonProps、disableSelectorIconRotation | — | 已移除 |
isReadOnly | ComboBox | ComboBox 上的 isReadOnly prop |
fullWidth | ComboBox | ComboBox 上的 fullWidth prop |
isVirtualized、maxListboxHeight、itemHeight | — | 已移除 |
onClose、onClear | — | 改用其他事件处理函数 |
validationBehavior、validate | ComboBox | 写在 ComboBox 上的 prop |
9. Prop 变更(Autocomplete)
| v2 prop | v3 位置 | 说明 |
|---|---|---|
| — | id(在 ListBox.Item 上) | 状态用的项标识 |
| — | textValue(在 ListBox.Item 上) | 无障碍(提前输入) |
label | Label | 使用 Label 组件 |
description | Description | 使用 Description 组件 |
placeholder | Autocomplete | 根组件上的 placeholder prop |
selectedKey / onSelectionChange | value / onChange | Autocomplete 上已重命名 |
selectionMode | Autocomplete | "single"(默认)或 "multiple" |
inputValue、onInputChange | Autocomplete.Filter | 写在 Filter 上的 inputValue 与 onInputChange |
disabledKeys、isDisabled、isRequired、isInvalid、name | Autocomplete | 与 v2 相同 |
variant、color、size、radius | — | 已移除(请使用 Tailwind CSS);variant 支持 "primary" / "secondary" |
isClearable | Autocomplete.ClearButton | 内置子组件 |
selectorIcon | Autocomplete.Indicator | 将自定义图标作为 children 传入 |
onClear | Autocomplete | 根组件上的 onClear prop |
fullWidth | Autocomplete | 根组件上的 fullWidth prop |
classNames | — | 在各部件上使用 className |
popoverProps、listboxProps、inputProps | — | 直接在对应子组件上配置 |
迁移示例
受控选择(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>受控选择(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>带分组
<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>使用 useFilter(Autocomplete)
{/* v2 在内部处理筛选 */}<Autocomplete label="Animal"> <AutocompleteItem key="cat">Cat</AutocompleteItem> <AutocompleteItem key="dog">Dog</AutocompleteItem></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>组件剖析
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)总结
- 两个替代组件:v2
Autocomplete可迁移为 v3ComboBox(内联输入)或 v3Autocomplete(Popover 内可筛选的选择器)。 - 组件结构:由带 prop 的单一组件变为带显式子节点的复合组件。
- 菜单项组件:
AutocompleteItem→ListBox.Item;AutocompleteSection→ListBox.Section。 - 菜单项标识:在项上使用
id与textValue;列表协调仍用 React 的key。 - 输入:v3 ComboBox 需要显式
Input;v3 Autocomplete 在Autocomplete.Filter内使用SearchField。 - 标签 / 描述:对应 prop 拆为独立的
Label与Description组件。 - 筛选:v3 Autocomplete 通过
Autocomplete.Filter与useFilter做区域设置感知筛选;v3 ComboBox 使用defaultFilterprop。 - 清除按钮:v3 Autocomplete 内置
Autocomplete.ClearButton;v3 ComboBox 需手动实现。 - 选中值展示:v3 Autocomplete 用
Autocomplete.Value展示选中值,并支持渲染 prop。 - 样式类 prop 已移除:
color、size、radius已移除(请使用 Tailwind CSS);variant现支持"primary"/"secondary"。 - classNames 已移除:在各子组件上使用
classNameprop。 - useFilter Hook:v3 新增,提供
contains、startsWith、endsWith用于区域设置感知的文本匹配。