输入类

自动完成

输入框自动填充。

使用场景

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

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

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

代码演示

如何引入

import { AutoComplete } from '@fibrous/semi-ui-solid';

基本用法

通过 onSearch 监听用户输入,将输入建议通过更新 data 传入。通过 value 与 onChange 保持受控,当输入框变化或选中输入项时会触发 onChange

代码
import { createSignal } from 'solid-js';
import { IconSearch } from '@fibrous/semi-icons-solid';
import { AutoComplete } from '@fibrous/semi-ui-solid';

const domains = ['gmail.com', '163.com', 'qq.com'];

export default function AutoCompleteDemo() {
    const [stringData, setStringData] = createSignal<string[]>([]);
    const [value, setValue] = createSignal<string | number>('');

    const handleStringSearch = (input: string) => {
        setStringData(input ? domains.map((domain) => `${input}@${domain}`) : []);
    };

    const handleChange = (next: string | number) => {
        console.log('onChange', next);
        setValue(next);
    };

    return <AutoComplete data={stringData()} value={value()} showClear prefix={<IconSearch />} placeholder="搜索... " onSearch={handleStringSearch} onChange={handleChange} style={{ width: '200px' }} />;
}

自定义候选项渲染

需要自定义候选项渲染时,data 可以传入一个对象数组(每个 Object 必须含有 label、value 两个 key,value 为候选项选中的值,label 为候选项展示的文本)。通过 renderItem 返回 JSX 可以自定义候选项的渲染

代码
import { createSignal } from 'solid-js';
import { IconSearch } from '@fibrous/semi-icons-solid';
import { AutoComplete, Avatar } from '@fibrous/semi-ui-solid';

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' },
];

export default function AutoCompleteDemo() {
    const [data, setData] = createSignal<ListItem[]>([]);

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

    const renderOption = (item: ListItem) => (
        <>
            <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>
        </>
    );

    return <AutoComplete aria-label="搜索邮箱" data={data()} showClear prefix={<IconSearch />} onSearch={handleStringSearch} renderItem={renderOption} renderSelectedItem={(option) => option.email} style={{ width: '280px' }} />;
}

远程搜索

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

尺寸

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





代码
import { AutoComplete } from '@fibrous/semi-ui-solid';

const data = [1, 2, 3, 4];

export default function AutoCompleteDemo() {
    return (
        <div>
            <AutoComplete data={data} size="small" placeholder="small" style={{ width: '200px' }} />
            <br />
            <br />
            <AutoComplete data={data} size="default" placeholder="default" style={{ width: '200px' }} />
            <br />
            <br />
            <AutoComplete data={data} size="large" placeholder="large" style={{ width: '200px' }} />
        </div>
    );
}

下拉菜单的位置

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

代码
import { createSignal } from 'solid-js';
import { AutoComplete } from '@fibrous/semi-ui-solid';

const domains = ['gmail.com', '163.com', 'qq.com'];

export default function AutoCompleteDemo() {
    const [data, setData] = createSignal<string[]>([]);

    const change = (input: string) => {
        setData(input ? domains.map((domain) => `${input}@${domain}`) : []);
    };

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

禁用

代码
import { AutoComplete } from '@fibrous/semi-ui-solid';

const data = [1, 2, 3, 4];

export default function AutoCompleteDemo() {
    return <AutoComplete data={data} placeholder="禁用下拉菜单" disabled style={{ width: '200px' }} />;
}

校验状态

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





代码
import { AutoComplete } from '@fibrous/semi-ui-solid';

export default function AutoCompleteDemo() {
    return (
        <>
            <AutoComplete aria-label="Warning status" defaultValue="ies" validateStatus="warning" />
            <br />
            <br />
            <AutoComplete aria-label="Error status" defaultValue="ies" validateStatus="error" />
            <br />
            <br />
            <AutoComplete aria-label="Default status" defaultValue="ies" />
        </>
    );
}

自定义空内容

可设置自定义展示空内容

代码
import { createSignal } from 'solid-js';
import { IllustrationNoContent } from '@fibrous/semi-illustrations-solid';
import { AutoComplete, Empty } from '@fibrous/semi-ui-solid';

export default function AutoCompleteDemo() {
    const [data, setData] = createSignal<number[]>([]);
    const [loading, setLoading] = createSignal(false);

    const fetchData = (input: string) => {
        setLoading(true);
        setTimeout(() => {
            setData(input ? Array.from({ length: 5 }, () => Math.random()) : []);
            setLoading(false);
        }, 1000);
    };

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

API 参考

Props

属性说明类型默认值
autoAdjustOverflow下拉面板被遮挡时是否自动调整方向。boolean-
autofocus挂载后是否自动聚焦输入框。booleanfalse
clearIcon自定义清除图标,showClear 为 true 时有效。JSX.Element-
data候选项的数据源,可以是字符串、数字或对象的数组。对象项的 value 是选中值,label 是候选行的文本(须提供,标记内容经 renderItem 渲染),其余字段原样保留,出现在 renderItem 的参数里。需替换为新数组才会更新列表。T[][]
defaultActiveFirstOption面板打开后是否默认高亮第一个候选项,此时按 Enter 可直接选中。booleanfalse
defaultOpen挂载时是否默认展开下拉面板。boolean-
defaultValue非受控时输入框的初始值,只在挂载时读取。string | number-
disabled是否禁用。boolean-
dropdownClassName下拉列表的类名,落在 role="listbox" 元素上。string-
dropdownMatchSelectWidth下拉面板的最小宽度是否等于输入框宽度。booleantrue
dropdownStyle下拉列表的内联样式,对象的键用 kebab-case,落在 role="listbox" 元素上。JSX.CSSProperties | string-
emptyContentdata 为空时在下拉面板中显示的内容;加载中时代替它显示加载动画。JSX.Elementnull
id输入框的 id,供 <label for> 关联;使用 triggerRender 时落在根元素上。string-
insetLabel输入框内嵌标签,渲染在前缀位置;设置 prefix 或 triggerRender 时不渲染,也不作为可访问名称。JSX.Element-
insetLabelIdinsetLabel 元素的 id,combobox 与 listbox 的名称引用它;不传时组件在渲染 insetLabel 时生成。string-
loading下拉列表是否显示加载动画;为 true 时代替候选项和空内容。booleanfalse
maxHeight下拉列表的最大高度,数字按 px 处理。string | number300
motion下拉面板显示、隐藏时是否有动画。booleantrue
onBlur焦点离开输入框所在区域时的回调,参数为 FocusEvent;焦点在区域内移动(例如移到清除按钮)时不触发。Type(e: FocusEvent) => void-
onChange输入框内容变化或选中候选项时的回调,参数为当前值。Type(value: string | number) => void-
onChangeWithObject不生效:组件不读取该属性。boolean-
onClear用清除按钮清空内容后的回调。Type() => void-
onDropdownVisibleChange下拉面板显示或隐藏时的回调,参数为是否可见。Type(visible: boolean) => void-
onFocus焦点进入输入框所在区域时的回调,参数为 FocusEvent;焦点在区域内移动(例如移到清除按钮)时不触发。Type(e: FocusEvent) => void-
onSearch用户输入时的回调,参数为输入的文本。Type(inputValue: string) => void-
onSelect候选项被选中时的回调,参数为选中值;设置 onSelectWithObject 时为去掉内部字段的数据项对象。Type(value: string | number | BaseDataItem) => void-
onSelectWithObject布尔属性,为 true 时 onSelect 收到去掉内部字段的数据项对象,而不是选中值。booleanfalse
placeholder输入框的提示文案。string-
position下拉面板的位置,可选值同 Tooltip 的 position。未设置时为 bottomLeft,ConfigProvider 的 direction 为 rtl 时为 bottomRight。Position-
prefix输入框的前缀内容;设置后 insetLabel 不渲染。JSX.Element-
ref根 div,包裹输入框或 triggerRender 的输出;其 focus() 与 blur() 作用于输入框。TypeRef<HTMLDivElement>-
renderItem自定义候选项的渲染,参数为数据项本身,返回 JSX 元素;未设置时显示 label。Type(option: T) => JSX.Element-
renderSelectedItem选中候选项后输入框显示的文本,必须返回字符串;字符串或数字项收到 { value, label },对象项收到数据项本身。Type(option: T extends string | number ? BaseDataItem : T) => string-
showClear有内容时是否显示清除按钮。booleanfalse
size输入框尺寸,可选 small、default 或 large。Size"default"
stopPropagation是否阻止下拉面板上的 click、mousedown 与焦点进出事件冒泡。TooltipProps['stopPropagation']true
suffix输入框的后缀内容。JSX.Element-
triggerRender自定义触发器,替换输入框。参数含 value(已选项数组)、inputValue、placeholder、disabled、autofocus、size、validateStatus、showClear、prefix、suffix、clearIcon、aria-label、aria-labelledby、aria-describedby、aria-errormessage、aria-invalid、aria-required(其他 aria-* 不会传到自定义触发器上)、onChange(更新输入文本,触发 onSearch 与 onChange 并展开列表)、onClear、onFocus、onBlur 与 componentProps。使用时 id 落在根元素上。Type(props: AutoCompleteTriggerRenderProps<T>) => JSX.Element-
validateStatus校验状态,可选 default、error 或 warning,只影响展示样式。ValidateStatus"default"
value当前值。传入后为受控,undefined 时按非受控处理。string | number-

class、style、ref、data-* 与其他未声明的属性和事件(例如 onClick)落在根 div 上,根 div 的 tabindex 固定为 -1。id、name 与 aria-* 落在输入框(role="combobox")上,因此 <label for> 能关联到输入框。使用 triggerRender 时没有输入框:id 落在根 div 上,name 不落到任何元素,aria-label、aria-labelledby、aria-describedby、aria-errormessage、aria-invalid 与 aria-required 通过参数交给自定义触发器的可聚焦元素,其他 aria-* 不会传到触发器上。

data 的对象项:

字段说明类型
value选中后的值string | number
label候选行的文本,须提供;标记内容经 renderItem 渲染string | number
disabled是否禁用该候选项boolean
class候选行的类名string
style候选行的样式JSX.CSSProperties | string

其他字段原样保留,出现在 renderItem 的参数里;设置 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)自动完成菜单选项文本颜色