---
title: Autocomplete 自动完成
description: 结合选择与过滤，让用户从选项列表中搜索并选择
links:
  rac: Select
  source: autocomplete/autocomplete.tsx
  styles: autocomplete.css
  storybook: Components/Pickers/Autocomplete
---

## 用法

```tsx
import { Autocomplete, useFilter } from "@heroui/react";
```

<ComponentPreview name="autocomplete-default" />

## 组件结构

```tsx
import {Autocomplete, Label, Description, SearchField, ListBox} from "@heroui/react";

export default () => (
  <Autocomplete>
    <Label />
    <Autocomplete.Trigger>
      <Autocomplete.Value />
      <Autocomplete.ClearButton />
      <Autocomplete.Indicator />
    </Autocomplete.Trigger>
    <Description />
    <Autocomplete.Popover>
      <Autocomplete.Filter>
        <SearchField>
          <SearchField.Group>
            <SearchField.SearchIcon />
            <SearchField.Input />
          </SearchField.Group>
        </SearchField>
        <ListBox>
          <ListBox.Item>
            <Label />
            <ListBox.ItemIndicator />
          </ListBox.Item>
        </ListBox>
      </Autocomplete.Filter>
    </Autocomplete.Popover>
  </Autocomplete>
);
```

## 示例

### 变体

Autocomplete 组件支持两种视觉变体：

- **`primary`**（默认）- 标准样式带阴影，适用于大多数场景
- **`secondary`** - 低强调变体无阴影，适用于 Surface 组件内

<ComponentPreview name="autocomplete-variants" />

### 宽度充满

<ComponentPreview name="autocomplete-full-width" />

### 带描述

<ComponentPreview name="autocomplete-with-description" />

### 必填

<ComponentPreview name="autocomplete-required" />

### 禁用

<ComponentPreview name="autocomplete-disabled" />

### 含禁用选项

<ComponentPreview name="autocomplete-with-disabled-options" />

### 允许空选项

`allowsEmptyCollection` 属性允许集合为空时仍可使用自动完成，适用于列表初始为空或全部被过滤掉的场景。

<ComponentPreview name="autocomplete-allows-empty-collection" />

### 分组选项

<ComponentPreview name="autocomplete-with-sections" />

### 多选

<ComponentPreview name="autocomplete-multiple-select" />

<Callout type="warning">
  在多选模式下，直接使用 `<Autocomplete.Value />` 会将每个选中项在 `ListBox.Item` 中的 children
  复制到触发器中，并以符合当前语言环境的分隔符连接。仅包含文本的选项会显示为纯文本，但复选框、头像等可见内容会随每个选中项各出现一次；函数形式的
  children 也始终以 `isSelected: false` 调用。
</Callout>

如需以纯文本显示选中值，请使用 `selectedText` 渲染属性，它会将每个选中项的 `textValue` 连接为一个字符串：

```tsx
<Autocomplete.Value>
  {({isPlaceholder, defaultChildren, selectedText}) =>
    isPlaceholder ? defaultChildren : selectedText
  }
</Autocomplete.Value>
```

如需可移除标签等更丰富的布局，请参考上方示例，基于 `state.selectedItems` 自行渲染内容。

### 受控组件

<ComponentPreview name="autocomplete-controlled" />

### 受控多选

<ComponentPreview name="autocomplete-controlled-multiple" />

### 受控展开状态

<ComponentPreview name="autocomplete-controlled-open-state" />

### 异步搜索

<ComponentPreview name="autocomplete-asynchronous-filtering" />

### 自定义指示器

<ComponentPreview name="autocomplete-custom-indicator" />

### 自定义展示值

可使用 render props 自定义显示值：

<ComponentPreview name="autocomplete-custom-value" />

### 表面样式

在 [Surface](/docs/components/surface) 组件内使用时，请使用 `variant="secondary"` 以应用适合 Surface 背景的低强调变体。

<ComponentPreview name="autocomplete-on-surface" />

### 虚拟滚动

Autocomplete 通过 [Virtualizer](https://react-aria.adobe.com/Virtualizer) 支持虚拟化，仅渲染视口内可见行以高效处理大数据集。

<ComponentPreview name="autocomplete-virtualization" />

## 高级示例

### 用户选择

<ComponentPreview name="autocomplete-user-selection" />

### 用户多选

<ComponentPreview name="autocomplete-user-selection-multiple" />

### 地点搜索

<ComponentPreview name="autocomplete-location-search" />

### 标签组选择

<ComponentPreview name="autocomplete-tag-group-selection" />

### 邮件收件人

<ComponentPreview name="autocomplete-email-recipients" />

## 自定义样式

### Tailwind CSS

<ComponentPreview name="autocomplete-custom-styles" />

### 全局 CSS

可使用 `@layer components` 指令自定义 Autocomplete 组件类。

[了解更多](https://tailwindcss.com/docs/adding-custom-styles#adding-component-classes)。

```css
@layer components {
  .autocomplete {
    @apply flex flex-col gap-1;
  }

  .autocomplete__trigger {
    @apply rounded-lg border border-border bg-surface p-2;
  }

  .autocomplete__value {
    @apply text-current;
  }

  .autocomplete__clear-button {
    @apply text-muted hover:text-foreground;
  }

  .autocomplete__indicator {
    @apply text-muted;
  }

  .autocomplete__popover {
    @apply rounded-lg border border-border bg-surface p-2;
  }
}
```

## 样式参考

HeroUI 遵循 [BEM](https://getbem.com/) 方法论，确保组件变体与状态可复用且易于自定义。

### CSS 类

Autocomplete 组件使用以下 CSS 类（[查看源码样式](https://github.com/heroui-inc/heroui/blob/v3/packages/styles/components/autocomplete.css)）：

#### 基础类 [!toc]

- `.autocomplete` - 自动完成根容器
- `.autocomplete__trigger` - 触发自动完成的按钮
- `.autocomplete__value` - 显示的值或占位符
- `.autocomplete__clear-button` - 清除已选值的按钮
- `.autocomplete__indicator` - 下拉指示图标
- `.autocomplete__popover` - 弹出层容器
- `.autocomplete__filter` - 过滤包装器

#### 变体类 [!toc]

- `.autocomplete--primary` - 带阴影的主变体（默认）
- `.autocomplete--secondary` - 无阴影的次变体，适用于 Surface 内

#### 状态类 [!toc]

- `.autocomplete[data-invalid="true"]` - 无效状态
- `.autocomplete__trigger[data-focus-visible="true"]` - 触发器聚焦状态
- `.autocomplete__trigger[data-disabled="true"]` - 触发器禁用状态
- `.autocomplete__value[data-placeholder="true"]` - 占位符状态
- `.autocomplete__clear-button[data-empty="true"]` - 无选择时隐藏清除按钮
- `.autocomplete__indicator[data-open="true"]` - 打开时的指示器状态

### 交互状态

组件同时支持 CSS 伪类与 data 属性：

- **Hover**：触发器上的 `:hover` 或 `[data-hovered="true"]`
- **Focus**：触发器上的 `:focus-visible` 或 `[data-focus-visible="true"]`
- **Disabled**：Autocomplete 上的 `:disabled` 或 `[data-disabled="true"]`
- **Open**：指示器上的 `[data-open="true"]`

## API 参考

### Autocomplete

| Prop | 类型 | 默认值 | 描述 |
|------|------|--------|------|
| `placeholder` | `string` | `'Select an item'` | 为空时显示的占位文本 |
| `selectionMode` | `"single" \| "multiple"` | `"single"` | 启用单选或多选 |
| `allowsEmptyCollection` | `boolean` | `false` | 是否允许空集合；为 true 时无选项也可使用 |
| `isOpen` | `boolean` | - | 弹出层打开状态（受控） |
| `defaultOpen` | `boolean` | - | 弹出层默认打开状态（非受控） |
| `onOpenChange` | `(isOpen: boolean) => void` | - | 打开状态变化时的回调 |
| `disabledKeys` | `Iterable<Key>` | - | 禁用项的 key |
| `isDisabled` | `boolean` | - | 是否禁用 |
| `value` | `Key \| Key[] \| null` | - | 当前值（受控） |
| `defaultValue` | `Key \| Key[] \| null` | - | 默认值（非受控） |
| `onChange` | `(value: Key \| Key[] \| null) => void` | - | 值变化时的回调 |
| `isRequired` | `boolean` | - | 是否必填 |
| `isInvalid` | `boolean` | - | 值是否无效 |
| `name` | `string` | - | 提交 HTML 表单时使用的名称 |
| `fullWidth` | `boolean` | `false` | 是否占满容器宽度 |
| `variant` | `"primary" \| "secondary"` | `"primary"` | 视觉变体。`primary` 为默认带阴影样式；`secondary` 为低强调无阴影，适用于 Surface 内 |
| `className` | `string` | - | 附加 CSS 类 |
| `children` | `ReactNode \| RenderFunction` | - | 内容或 render 函数 |

### Autocomplete.Trigger

| Prop | 类型 | 默认值 | 描述 |
|------|------|--------|------|
| `className` | `string` | - | 附加 CSS 类 |
| `children` | `ReactNode \| RenderFunction` | - | 触发器内容或 render 函数 |

### Autocomplete.Value

| Prop | 类型 | 默认值 | 描述 |
|------|------|--------|------|
| `className` | `string` | - | 附加 CSS 类 |
| `children` | `ReactNode \| RenderFunction` | - | 值内容或 render 函数 |

### Autocomplete.Indicator

| Prop | 类型 | 默认值 | 描述 |
|------|------|--------|------|
| `className` | `string` | - | 附加 CSS 类 |
| `children` | `ReactNode` | - | 自定义指示器内容 |

### Autocomplete.ClearButton

| Prop | 类型 | 默认值 | 描述 |
|------|------|--------|------|
| `className` | `string` | - | 附加 CSS 类 |
| `onClick` | `(e: MouseEvent) => void` | - | 点击按钮时的回调 |
| `ref` | `RefObject<HTMLButtonElement>` | - | 清除按钮元素的 ref |

### Autocomplete.Popover

| Prop | 类型 | 默认值 | 描述 |
|------|------|--------|------|
| `placement` | `"bottom" \| "bottom left" \| "bottom right" \| "bottom start" \| "bottom end" \| "top" \| "top left" \| "top right" \| "top start" \| "top end" \| "left" \| "left top" \| "left bottom" \| "start" \| "start top" \| "start bottom" \| "right" \| "right top" \| "right bottom" \| "end" \| "end top" \| "end bottom"` | `"bottom"` | 弹出层相对触发器的位置 |
| `className` | `string` | - | 附加 CSS 类 |
| `children` | `ReactNode` | - | 子内容 |

### Autocomplete.Filter

| Prop | 类型 | 默认值 | 描述 |
|------|------|--------|------|
| `filter` | `(text: string, input: string) => boolean` | - | 自定义过滤函数 |
| `inputValue` | `string` | - | 受控输入值 |
| `onInputChange` | `(value: string) => void` | - | 输入值变化时的回调 |
| `children` | `ReactNode` | - | 过滤内容（SearchField 与 ListBox） |

### useFilter Hook

React Aria 的 `useFilter` hook 提供自动完成过滤函数。

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

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

<Autocomplete.Filter filter={contains}>
  <SearchField>...</SearchField>
  <ListBox>...</ListBox>
</Autocomplete.Filter>
```

**Options:**

| Option | 类型 | 默认值 | 描述 |
|--------|------|--------|------|
| `sensitivity` | `"base" \| "accent" \| "case" \| "variant"` | `"base"` | 匹配的 locale 敏感度 |

**Returns:**

| Function | 类型 | 描述 |
|----------|------|------|
| `contains` | `(string: string, substring: string) => boolean` | 判断字符串是否包含子串 |
| `startsWith` | `(string: string, substring: string) => boolean` | 判断字符串是否以子串开头 |
| `endsWith` | `(string: string, substring: string) => boolean` | 判断字符串是否以子串结尾 |

### Render Props

使用 Autocomplete.Value 的 render 函数时，提供以下值：

| Prop | 类型 | 描述 |
| --- | --- | --- |
| `defaultChildren` | `ReactNode` | 默认渲染的值。多选模式下为每个选中项 children 的副本，以符合当前语言环境的分隔符连接 |
| `isPlaceholder` | `boolean` | 是否为占位符 |
| `state` | `SelectState` | 自动完成的状态。如需获取选中的集合节点，请使用 `state.selectedItems` |
| `selectedItems` | `(T \| null)[]` | 当前选中项的值 |
| `selectedText` | `string` | 选中项的 `textValue`，以符合当前语言环境的分隔符连接 |

## 无障碍

Autocomplete 组件实现带过滤的 ARIA select 模式，提供：

- 完整键盘导航支持
- 选择变化的屏幕阅读器播报
- 正确的焦点管理
- 禁用状态支持
- 带过滤的搜索功能
- HTML 表单集成

更多信息请参阅 [React Aria Select 文档](https://react-spectrum.adobe.com/react-aria/Select.html)。

## 相关组件

<RelatedComponents component="autocomplete" />