SuperAPI AI 工具集

multi-select-input

前端与建站

查看项目

更新于 10-16 05:26

技能介绍

用途

多选输入(Multi-select Input)是一种表单组件,允许用户从一组预定义选项中选取多个条目。它与自动补全(Autocomplete)不同:自动补全为自由输入提供建议,而多选输入作用于一个有边界、已知的选项列表,用户只能选择列表中已存在的内容。

最常见的视觉实现是基于标签/芯片(tag/chip)的选择器:已选条目以可移除标签的形式显示在输入框内,剩余选项在下拉列表中展示。其他实现模式还包括复选框列表、双列表(dual listbox)以及原生 <select multiple>。

适用场景

  • 分类与标签分配:为内容分配标签、标记或分类。
  • 权限与角色管理:为用户选择多个角色。
  • 筛选面板:让用户同时应用多个筛选条件。
  • 收件人选择:从联系人列表中选择多个邮件收件人。
  • 功能选择:配置要启用哪些功能/模块。

不适用场景

  • 带建议的自由文本输入:应改用自动补全(Autocomplete)。
  • 从少量选项中单选:应改用下拉选择(Select/Dropdown)或单选按钮组(Radio group)。
  • 二选一:应改用复选框(Checkboxes)。
  • 超大选项集(超过 1000 项):应改用虚拟化列表或以搜索为先的方案。

实现流程

  1. 在复制示例前,先确认该模式与问题及约束条件匹配。
  2. 从 references/pattern.md 中的结构与示例入手,选择最小可行的变体。
  3. 在叠加视觉打磨之前,先应用无障碍、性能和交互方面的防护措施。
  4. 使用测试指南验证键盘、屏幕阅读器、响应式及失败场景下的行为。

无障碍防护

键盘交互模式:

按键 操作
Tab 将焦点移至多选输入;Shift+Tab 反向移动
下箭头 打开下拉列表;向下移动焦点遍历选项
上箭头 向上移动焦点遍历选项
Enter 选中/取消选中当前聚焦的选项
Space 选中/取消选中当前聚焦的选项(在列表框中与 Enter 相同)
Escape 关闭下拉列表且不改变选择
Backspace 当搜索输入为空时,移除最后一个已选标签

性能防护

  • 下拉打开时间:< 100ms
  • 选项过滤(搜索):对于最多 1000 项的列表 < 50ms
  • 标签添加渲染:< 16ms(一帧)
  • 全选操作:对于 100 项 < 50ms
  • 每个实例内存:组件 < 15KB;选项超过 500 项时对选项列表进行虚拟化

常见错误

使用 <select multiple>

问题:原生 <select multiple> 需要 Ctrl+Click(或 Cmd+Click)才能多选,这是一种大多数用户并不知晓的、不直观的交互。

<!-- Bad: Requires Ctrl+click — users don't know this -->
<select multiple name="skills[]">
  <option>React</option>
  <option>TypeScript</option>
</select>

修复方式:使用带复选框或基于标签 UI 的自定义多选组件。

每次选择后关闭下拉列表

问题:如果用户每选一项下拉列表就关闭,他们必须为每个额外选择重新打开它,这会显著拖慢多选工作流。

修复方式:选择后保持下拉列表打开;仅在 Escape 或外部点击时关闭。

option.addEventListener('click', (e) => {
  e.stopPropagation(); // Prevent close-on-outside-click from triggering
  toggleOptionSelection(option);
  updateTags();
  searchInput.focus(); // Keep focus in the input
  // DO NOT close the dropdown here
});

未处理 Backspace 移除标签

问题:用户期望在空搜索输入中按 Backspace 能移除最后一个已选标签。缺少此功能会让组件显得不完整,并迫使用户使用鼠标。

修复方式:监听搜索输入上的 keydown 事件。

searchInput.addEventListener('keydown', (e) => {
  if (e.key === 'Backspace' && searchInput.value === '') {
    const lastTag = getLastSelectedItem();
    if (lastTag) {
      removeSelection(lastTag);
    }
  }
});

相关模式

  • https://uxpatterns.dev/patterns/forms/autocomplete
  • https://uxpatterns.dev/patterns/forms/checkbox
  • https://uxpatterns.dev/patterns/forms/radio
  • https://uxpatterns.dev/patterns/forms/selection-input

完整实现细节、示例和测试说明,请参见 references/pattern.md。

模式页面:https://uxpatterns.dev/patterns/forms/multi-select-input