import { Autocomplete } from "@cloudflare/kumo";
/** Basic autocomplete with a flat list of strings. */
export function AutocompleteDemo() {
return (
<Autocomplete items={fruits}>
<Autocomplete.InputGroup placeholder="Search fruits…" />
<Autocomplete.Content>
<Autocomplete.List>
{(item: string) => (
<Autocomplete.Item key={item} value={item}>
{item}
</Autocomplete.Item>
)}
</Autocomplete.List>
</Autocomplete.Content>
</Autocomplete>
);
}安装
批量导入
import { Autocomplete } from "@cloudflare/kumo";细粒度导入
import { Autocomplete } from "@cloudflare/kumo/components/autocomplete";何时使用
当输入值可以是自由文本、建议仅作为可选提示时,使用 Autocomplete。当选定值必须来自预定义列表时,请改用 Combobox。
受控用法
传入 value 和 onValueChange 即可进行受控使用。
import { useState } from "react";
import { Autocomplete } from "@cloudflare/kumo";
/** Controlled autocomplete with value and onValueChange. */
export function AutocompleteControlledDemo() {
const [value, setValue] = useState("");
return (
<div className="flex w-80 flex-col gap-3">
<Autocomplete
items={fruits}
value={value}
onValueChange={(v) => setValue(v)}
>
<Autocomplete.InputGroup placeholder="Type a fruit…" />
<Autocomplete.Content>
<Autocomplete.List>
{(item: string) => (
<Autocomplete.Item key={item} value={item}>
{item}
</Autocomplete.Item>
)}
</Autocomplete.List>
</Autocomplete.Content>
</Autocomplete>
{value && (
<p className="text-sm text-kumo-subtle">
Value: <span className="font-medium text-kumo-default">{value}</span>
</p>
)}
</div>
);
}启用 Field
添加 label、description 和 required 即可启用内置的 Field 包装。
Start typing to filter languages
import { useCallback } from "react";
import { Autocomplete } from "@cloudflare/kumo";
import { languages, Language } from "./data/languages";
/** Autocomplete with label, description, and Field wrapper. */
export function AutocompleteWithFieldDemo() {
const { contains } = Autocomplete.useFilter();
const filter = useCallback(
(item: Language, query: string) => contains(item.label, query),
[contains],
);
return (
<div className="w-80">
<Autocomplete
items={languages}
label="Language"
description="Start typing to filter languages"
filter={filter}
>
<Autocomplete.InputGroup placeholder="Search a language…" />
<Autocomplete.Content>
<Autocomplete.List>
{(item: Language) => (
<Autocomplete.Item key={item.value} value={item}>
{item.emoji} {item.label}
</Autocomplete.Item>
)}
</Autocomplete.List>
</Autocomplete.Content>
</Autocomplete>
</div>
);
}错误状态
使用 error 属性显示校验错误。
Please enter a valid country
import { useCallback } from "react";
import { Autocomplete } from "@cloudflare/kumo";
/** Autocomplete with error state via the Field wrapper. */
export function AutocompleteErrorDemo() {
const { contains } = Autocomplete.useFilter();
const filter = useCallback(
(item: Country, query: string) => contains(item.label, query),
[contains],
);
return (
<div className="w-80">
<Autocomplete
items={countries}
label="Country"
error={{ message: "Please enter a valid country", match: true }}
filter={filter}
>
<Autocomplete.InputGroup placeholder="Search countries…" />
<Autocomplete.Content>
<Autocomplete.List>
{(item: Country) => (
<Autocomplete.Item key={item.code} value={item}>
{item.label}
</Autocomplete.Item>
)}
</Autocomplete.List>
</Autocomplete.Content>
</Autocomplete>
</div>
);
}分组
使用 Autocomplete.Group 和 Autocomplete.GroupLabel 将条目按类别分组。
import { Autocomplete } from "@cloudflare/kumo";
/** Autocomplete with grouped items using Group and GroupLabel. */
export function AutocompleteGroupedDemo() {
return (
<Autocomplete items={servers}>
<Autocomplete.InputGroup placeholder="Select region…" />
<Autocomplete.Content>
<Autocomplete.List>
{(group: ServerGroup) => (
<Autocomplete.Group key={group.value} items={group.items}>
<Autocomplete.GroupLabel>{group.value}</Autocomplete.GroupLabel>
<Autocomplete.Collection>
{(item: ServerLocation) => (
<Autocomplete.Item key={item.value} value={item}>
{item.label}
</Autocomplete.Item>
)}
</Autocomplete.Collection>
</Autocomplete.Group>
)}
</Autocomplete.List>
</Autocomplete.Content>
</Autocomplete>
);
}尺寸
Autocomplete.InputGroup 上的 size 属性支持四种变体,与 Input
组件保持一致:xs、sm、base(默认)和 lg。
import { Autocomplete } from "@cloudflare/kumo";
/** Demonstrates the four size variants: xs, sm, base, and lg. */
export function AutocompleteSizesDemo() {
return (
<div className="flex flex-wrap items-center gap-4">
<Autocomplete items={fruits.slice(0, 10)}>
<Autocomplete.InputGroup size="xs" placeholder="xs" />
<Autocomplete.Content>
<Autocomplete.List>
{(item: string) => (
<Autocomplete.Item key={item} value={item}>
{item}
</Autocomplete.Item>
)}
</Autocomplete.List>
</Autocomplete.Content>
</Autocomplete>
<Autocomplete items={fruits.slice(0, 10)}>
<Autocomplete.InputGroup size="sm" placeholder="sm" />
<Autocomplete.Content>
<Autocomplete.List>
{(item: string) => (
<Autocomplete.Item key={item} value={item}>
{item}
</Autocomplete.Item>
)}
</Autocomplete.List>
</Autocomplete.Content>
</Autocomplete>
<Autocomplete items={fruits.slice(0, 10)}>
<Autocomplete.InputGroup size="base" placeholder="base (default)" />
<Autocomplete.Content>
<Autocomplete.List>
{(item: string) => (
<Autocomplete.Item key={item} value={item}>
{item}
</Autocomplete.Item>
)}
</Autocomplete.List>
</Autocomplete.Content>
</Autocomplete>
<Autocomplete items={fruits.slice(0, 10)}>
<Autocomplete.InputGroup size="lg" placeholder="lg" />
<Autocomplete.Content>
<Autocomplete.List>
{(item: string) => (
<Autocomplete.Item key={item} value={item}>
{item}
</Autocomplete.Item>
)}
</Autocomplete.List>
</Autocomplete.Content>
</Autocomplete>
</div>
);
}过滤
过滤默认不区分大小写和重音符号,底层由 Intl.Collator
驱动。对于字符串条目,无需自定义 filter。
当按对象条目的某个属性进行过滤时,使用 Autocomplete.useFilter()
以保留内置的重音不敏感匹配:
function LanguagePicker() {
const { contains } = Autocomplete.useFilter();
const filter = useCallback(
(item: Language, query: string) => contains(item.label, query),
[contains],
);
return (
<Autocomplete items={languages} filter={filter}>
{/* ... */}
</Autocomplete>
);
}若要完全禁用过滤(例如结果来自服务器),传入 filter={null}:
<Autocomplete items={results} filter={null}>
...
</Autocomplete>API 参考
Autocomplete
根组件。包裹所有子组件并管理状态。
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| items* | unknown[] | - | Array of items to display in the dropdown |
| value | string | number | string[] | - | The controlled input value |
| open | boolean | - | Whether the popup is open (controlled) |
| children | ReactNode | - | Autocomplete content (input group, popup content) |
| className | string | - | Additional CSS classes |
| label | ReactNode | - | Label content (enables Field wrapper) |
| required | boolean | - | Whether the field is required |
| labelTooltip | ReactNode | - | Tooltip content to display next to the label |
| description | ReactNode | - | Helper text displayed below the field |
| error | string | object | - | Error message or validation error object |
Autocomplete.InputGroup
自包含的输入包装器,把文本输入框、清除按钮和下拉触发器组合在一起渲染。
| 属性 | 类型 | 默认值 |
|---|---|---|
| className | string | - |
| size | KumoAutocompleteSize | - |
| placeholder | string | - |
Autocomplete.Content
下拉浮层容器。包裹 Portal、Positioner 和 Popup。
| 属性 | 类型 | 默认值 |
|---|---|---|
| children | ReactNode | - |
| className | string | - |
| align | AutocompleteBase.Positioner.Props["align"] | - |
| alignOffset | AutocompleteBase.Positioner.Props["alignOffset"] | - |
| side | AutocompleteBase.Positioner.Props["side"] | - |
| sideOffset | AutocompleteBase.Positioner.Props["sideOffset"] | - |
Autocomplete.Item
列表中的单个建议条目。
| 属性 | 类型 | 默认值 |
|---|
该组件没有专属属性,接受标准 HTML 属性。
其他子组件
Autocomplete.List— 可滚动的列表容器,带 render 属性Autocomplete.Group— 把条目归到一个标题下分组Autocomplete.GroupLabel— 分组的标题标签Autocomplete.Collection— 分组内的条目容器Autocomplete.Separator— 条目之间的水平分隔线