输入类

自动完成

输入框自动填充。

使用场景

用于对输入框提供输入建议,进行自动补全的操作

与可搜索的 Select 组件的区别:

  • AutoComplete 本质上是一个增强型的提供了输入建议的 Input 组件,而 Select 是一个选择器
  • 点击展开时,Select 会将输入框的值全部清空,而 AutoComplete 会保留上次选中的值
  • Select 的已选项渲染可以是任意 snippet 内容,而 AutoComplete 的 renderSelectedItem 只允许返回字符串

代码演示

如何引入

<script lang="ts">
    import { AutoComplete } from '@fibrae/semi-ui-svelte';
</script>

基本用法

通过 onSearch 监听用户输入,将输入建议通过更新 data 传入。通过 bind:value 保持值同步,当输入框变化或选中输入项时会更新。没有 defaultValue:单向 value={x} 只作初值,要完全受控用函数绑定 bind:value={get, set}

当前输入:

代码
<script lang="ts">
    import { IconSearch } from '@fibrae/semi-icons-svelte';
    import { AutoComplete } from '@fibrae/semi-ui-svelte';

    let stringData = $state<string[]>([]);
    let value = $state<string | number>('');

    const handleStringSearch = (input: string) => {
        stringData = input ? ['gmail.com', '163.com', 'qq.com'].map((domain) => `${input}@${domain}`) : [];
    };
</script>

<AutoComplete bind:value data={stringData} onSearch={handleStringSearch} placeholder="搜索... " showClear style="width: 200px">
    {#snippet prefix()}
        <IconSearch />
    {/snippet}
</AutoComplete>
<p>当前输入:{value}</p>

自定义候选项渲染

需要自定义候选项渲染时,data 可以传入一个对象数组(每个 Object 含有 label、value 两个 key,value 为候选项选中的值,label 为候选项展示的文本,缺省时回落到 value)
通过 item snippet(参数为 { item, index })可以自定义候选项内容:item 是未经加工的数据项,数据项里只放数据,标记写在 snippet 里

代码
<script lang="ts">
    import { IconSearch } from '@fibrae/semi-icons-svelte';
    import { AutoComplete, Avatar } from '@fibrae/semi-ui-svelte';

    interface ListItem {
        name: string;
        email: string;
        abbr: string;
        color: 'amber' | 'indigo' | 'blue' | 'cyan';
        value?: string;
        label?: string;
    }

    const list: ListItem[] = [
        { name: '夏可漫', email: 'xiakeman@example.com', abbr: 'XK', color: 'amber' },
        { name: '申悦', email: 'shenyue@example.com', abbr: 'SY', color: 'indigo' },
        { name: '曲晨一', email: 'quchenyi@example.com', abbr: 'CY', color: 'blue' },
        { name: '文嘉茂', email: 'wenjiamao@example.com', abbr: 'JM', color: 'cyan' },
    ];

    let data = $state<ListItem[]>([]);

    const handleStringSearch = (value: string) => {
        data = value ? list.map((item) => ({ ...item, value: item.name, label: item.email })) : [];
    };

    const renderSelectedItem = (option: ListItem) => option.email;
</script>

<AutoComplete aria-label="搜索邮箱" {data} onSearch={handleStringSearch} {renderSelectedItem} showClear style="width: 280px">
    {#snippet prefix()}
        <IconSearch />
    {/snippet}
    {#snippet item({ item })}
        <Avatar color={item.color} size="small">{item.abbr}</Avatar>
        <div style="margin-left: 4px">
            <div style="font-size: 14px; margin-left: 4px">{item.name}</div>
            <div style="margin-left: 4px">{item.email}</div>
        </div>
    {/snippet}
</AutoComplete>

远程搜索

从 onSearch 中获取用户输入值,动态更新 data,并更新 loading

尺寸

通过设置 size 可设置输入框尺寸,可选small,default(默认),large





代码
<script lang="ts">
    import { AutoComplete } from '@fibrae/semi-ui-svelte';

    const data = [1, 2, 3, 4];
</script>

<div>
    <AutoComplete {data} placeholder="small" size="small" style="width: 200px" />
    <br />
    <br />
    <AutoComplete {data} placeholder="default" size="default" style="width: 200px" />
    <br />
    <br />
    <AutoComplete {data} placeholder="large" size="large" style="width: 200px" />
</div>

下拉菜单的位置

通过设置 position 可设置下拉菜单位置,可选值参考 Tooltip position

代码
<script lang="ts">
    import { AutoComplete } from '@fibrae/semi-ui-svelte';

    let data = $state<string[]>([]);

    const change = (input: string) => {
        data = input ? ['gmail.com', '163.com', 'qq.com'].map((domain) => `${input}@${domain}`) : [];
    };
</script>

<div>
    <AutoComplete {data} onSearch={change} placeholder="选项菜单在上方显示" position="top" style="width: 200px; margin: 10px" />
    <AutoComplete {data} onSearch={change} placeholder="选项菜单在右侧显示" position="rightTop" style="width: 200px; margin: 10px" />
</div>

禁用

代码
<script lang="ts">
    import { AutoComplete } from '@fibrae/semi-ui-svelte';

    const data = [1, 2, 3, 4];
</script>

<AutoComplete {data} disabled placeholder="禁用下拉菜单" style="width: 200px" />

校验状态

可设置不同校验状态,展示不同样式





代码
<script lang="ts">
    import { AutoComplete } from '@fibrae/semi-ui-svelte';

    let warning = $state('ies');
    let error = $state('ies');
    let normal = $state('ies');
</script>

<AutoComplete aria-label="Warning status" bind:value={warning} validateStatus="warning" />
<br />
<br />
<AutoComplete aria-label="Error status" bind:value={error} validateStatus="error" />
<br />
<br />
<AutoComplete aria-label="Default status" bind:value={normal} />

自定义空内容

可设置自定义展示空内容

代码
<script lang="ts">
    import { IllustrationNoContent } from '@fibrae/semi-illustrations-svelte';
    import { AutoComplete, Empty } from '@fibrae/semi-ui-svelte';

    let data = $state<number[]>([]);
    let loading = $state(false);

    const fetchData = (input: string) => {
        loading = true;
        setTimeout(() => {
            data = input ? Array.from({ length: 5 }, () => Math.random()) : [];
            loading = false;
        }, 1000);
    };
</script>

<AutoComplete aria-label="搜索" {data} {loading} onSearch={fetchData}>
    {#snippet emptyContent()}
        <Empty style="padding: 12px; width: 300px">
            {#snippet image()}
                <IllustrationNoContent style="width: 150px; height: 150px" />
            {/snippet}
            {#snippet description()}暂无内容{/snippet}
        </Empty>
    {/snippet}
</AutoComplete>

API 参考

Props

属性说明类型默认值
autoAdjustOverflow下拉面板被遮挡时是否自动调整方向。boolean-
autofocus是否在挂载后自动聚焦输入框。booleanfalse
clearIcon自定义清除图标的 snippet,showClear 为 true 时有效。Snippet-
data候选项的数据源,可以是字符串、数字或对象的数组。对象项用 value 作选中值,label 作展示文本(缺省显示 value),disabled、class、style 与 data-* 字段落在对应的候选行上,class 接受字符串、数组或对象,style 是字符串;节点内容用 item snippet。T[][]
defaultActiveFirstOption面板打开后是否默认高亮第一个候选项,此时按 Enter 可直接选中。booleanfalse
defaultOpen挂载时是否默认展开下拉面板;AutoComplete 没有受控的展开状态。boolean-
disabled是否禁用。boolean-
dropdownClassName下拉列表的类名,落在 role="listbox" 元素上。string-
dropdownMatchSelectWidth下拉面板的最小宽度是否等于输入框宽度。booleantrue
dropdownStyle下拉列表的内联样式字符串,落在 role="listbox" 元素上。string-
emptyContentdata 为空时在下拉面板中显示的内容的 snippet。Snippet-
insetLabel输入框内嵌标签的 snippet,只要传入就当作有内容。设置 prefix 或 trigger 时不渲染,也不作为可访问名称。Snippet-
insetLabelIdinsetLabel 前缀元素的 id,combobox 与 listbox 的名称引用它;不传时组件在渲染 insetLabel 时生成。string-
item候选项行内容的 snippet,参数 { item, index }:item 是未经加工的数据项,index 是它在已渲染候选项中的位置;不提供时显示 label。TypeSnippet<[AutoCompleteItemSnippetProps<T>]>-
loading下拉列表是否显示加载动画;为 true 时代替候选项和空内容。booleanfalse
maxHeight下拉列表的最大高度,数字按 px 处理。string | number300
motion下拉面板显示、隐藏时是否有动画。booleantrue
onBlur焦点离开输入框时调用一次。Type(event: FocusEvent) => void-
onChange输入框内容变化或选中候选项时调用。Type(value: string | number) => void-
onClear用清除按钮清空内容后调用。Type() => void-
onDropdownVisibleChange下拉面板显示或隐藏时调用,参数为是否可见。Type(visible: boolean) => void-
onFocus焦点进入输入框时调用一次。Type(event: FocusEvent) => void-
onSearch用户输入时调用,参数为输入的文本。Type(inputValue: string) => void-
onSelect选中候选项时调用,参数为选中值;设置 onSelectWithObject 时为去掉内部字段的数据项。Type(value: string | number | AutoCompleteDataItem) => void-
onSelectWithObject布尔属性,不是回调:为 true 时,onSelect 收到去掉内部字段的数据项对象,而不是选中值。booleanfalse
placeholder输入框的提示文案。string-
position下拉面板的位置,可选值同 Tooltip 的 position。未设置时为 bottomLeft,ConfigProvider 的 direction 为 rtl 时为 bottomRight。Position-
prefix输入框前缀的 snippet。Snippet-
renderSelectedItem选中候选项后输入框显示的文本,必须返回字符串;字符串或数字项收到 { value, label },对象项收到数据项本身。Type(option: AutoCompleteSelectedItem<T>) => string-
showClear有内容时是否显示清除按钮。booleanfalse
size输入框尺寸。Size-
stopPropagation是否阻止下拉面板上的 click、mousedown 与焦点进出事件冒泡。boolean | stringtrue
suffix输入框后缀的 snippet。Snippet-
trigger替换输入框的 snippet。参数含 value、inputValue、placeholder、disabled、autofocus、size、validateStatus、showClear、insetLabelId、onChange(更新输入文本,触发 onSearch 与 onChange 并展开列表)、onClear、onFocus、onBlur、controlAttrs(传给组件的 aria-* 属性,放到自定义触发器的可聚焦元素上)。使用时 id 落在根元素上。TypeSnippet<[AutoCompleteTriggerSnippetProps]>-
validateStatus校验状态,只影响展示样式。ValidateStatus"default"
value输入框的当前值,可 bind:value。不传时由组件自行管理;单向 value={x} 只作初值,要完全受控用函数绑定 bind:value={get, set}。没有 defaultValue。string | number-

Methods

方法说明类型
blur使输入框失去焦点。Type() => void
focus使输入框获得焦点。Type(options?: FocusOptions) => void
getNativeElement返回根 div,它包裹输入框或自定义触发器。Type() => HTMLDivElement | undefined

id、name 以及 aria-describedby、aria-errormessage、aria-invalid、aria-label、aria-labelledby、aria-required 落在输入框(role="combobox")上,因此 <label for> 能关联到输入框。class(字符串、数组或对象)、style(字符串)、data-* 与其他未声明的属性和事件处理(例如 onclick)落在根 div 上,根 div 的 tabindex 固定为 -1;onkeydown 在组件处理完按键之后调用。小写的 onfocus、onblur、onchange、onselect 不是原生透传,请使用回调 onFocus、onBlur、onChange、onSelect。使用 trigger snippet 时没有输入框:id 落在根 div 上,name 不落到任何元素,aria-* 通过 controlAttrs 参数交给自定义触发器的可聚焦元素。

data 的对象项:

字段说明类型
value选中后的值string | number
label候选项的文本,缺省回落到 value;标记请用 item snippetstring | number
disabled是否禁用该候选项boolean
class候选行的类名string | object | array
style候选行的样式string

其他字段原样保留,出现在 item snippet 的 item 里;设置 onSelectWithObject 时,onSelect 收到的数据项对象同样保留这些字段。以 data- 开头的字段落在候选行上。字符串和数字项在 renderSelectedItem 中以 { value, label } 形式收到。

Accessibility

键盘和焦点

  • AutoComplete 的 input 框带有 role="combobox",并通过 aria-expanded、aria-controls、aria-autocomplete="list" 和 aria-activedescendant 与选项面板关联
  • combobox 的名称按优先级取:aria-labelledby、aria-label、实际渲染出来的 insetLabel(combobox 的 aria-labelledby 指向它,未传 insetLabelId 时组件生成 id;有 prefix 时 insetLabel 不渲染,也不作名称)。listbox 使用同一个名称来源。AutoComplete 没有默认名称:以上都没有时,请用 aria-label 或 aria-labelledby 为输入框命名;<label for> 只命名输入框,listbox 仍没有名称
  • AutoComplete 的 input 框可被聚焦,聚焦后,键盘用户可以通过 上箭头 或 下箭头 打开选项面板;data 为空时面板里显示 emptyContent(没有提供时为空),加载中显示加载动画
  • AutoComplete 也支持通过 Enter 键打开和收起面板
  • 若用户将 defaultActiveFirstOption 属性设置为 true 时,选项面板打开后默认高亮第一个选项
  • 若下拉菜单打开时:
    • 使用 Esc 可以关闭菜单
    • 使用 Tab 可以关闭菜单,焦点照常移到下一个可聚焦元素
    • 使用 上箭头 或 下箭头 可以切换选项,被高亮的选项(aria-activedescendant 指向的项)aria-selected 为 true
    • 被聚焦的选项可以通过 Enter 键选中,并收起面板
    • 用鼠标选中选项后,焦点留在输入框中
  • showClear 开启且有内容时,清除按钮与 Input 相同:原生 button,名称为语言包中的「清空输入」,从输入框按 Tab 移到它,Enter 或空格键清空并把焦点放回输入框

文案规范

  • 需要清晰地展示内容,让用户显而易见地感知到可用的各个选项
  • 限制一次性展示的选项数量

设计变量

下表是组件内部的 Sass 变量,不能覆写。定制样式请覆写 --semi-* CSS 变量(见 Design Token 页),或写不分层的 CSS 规则。
Sass 变量值用法
$transition_duration-autoComplete_option-bgvar(--semi-transition_duration-none)选择器-选项-动画持续时间
$transition_function-autoComplete_option-bgvar(--semi-transition_function-easeIn)选择器-选项-过渡曲线
$transition_delay-autoComplete_option-bgvar(--semi-transition_delay-none)选择器-选项-延迟时间
$spacing-autoComplete_loading_wrapper-paddingTop$spacing-tight加载搜索结果时的顶部内边距
$spacing-autoComplete_loading_wrapper-paddingBottom$spacing-tight加载搜索结果时的底部内边距
$color-autoComplete_option-icon-defaulttransparent自动完成菜单选项图标颜色 - 默认态
$color-autoComplete_option-bg-hovervar(--semi-color-fill-0)自动完成菜单选项背景颜色 - 悬停态
$color-autoComplete_option-bg-activevar(--semi-color-fill-1)自动完成菜单选项背景颜色 - 按下态
$color-autoComplete_option_disabled-textvar(--semi-color-disabled-text)禁用自动完成菜单选项文字颜色
$width-autoComplete_option_tick$width-icon-small自动完成菜单项选中对勾图标大小
$spacing-autoComplete_option_tick-marginRight$spacing-tight自动完成菜单选中对勾右侧外边距
$spacing-autoComplete_option-paddingLeft$spacing-base-tight自动完成菜单项左侧内边距
$spacing-autoComplete_option-paddingRight$spacing-base-tight自动完成菜单项右侧内边距
$spacing-autoComplete_option-paddingTop$spacing-tight自动完成菜单项顶部内边距
$spacing-autoComplete_option-paddingBottom$spacing-tight自动完成菜单项底部内边距
$spacing-autoComplete_option_first-marginTop$spacing-extra-tight自动完成第一个菜单项顶部外边距
$spacing-autoComplete_option_last-marginBottom$spacing-extra-tight自动完成最后一个菜单项顶部外边距
$radius-autoComplete_option0px自动完成待选项圆角
$color-autoComplete_option_main-textvar(--semi-color-text-0)自动完成菜单选项文本颜色