Skip to content

下拉选择 Select

从一组选项中选择一个或多个。单选、多选使用同一个组件,都支持搜索,外观在所有浏览器和系统上一致。

单选

examples/select/single.html
  • 可以输入中文、英文或选项值搜索;在每个选项的 data-keywords 里补充英文名、拼音、别名,搜索会一并匹配
  • 可清除:加一个 data-cb-select-clear 按钮(有值时自动显示),文字区域 data-cb-select-valuepr-7 给它留位置
  • 禁用某个选项:<option disabled>;禁用整个下拉:<select disabled>

多选

examples/select/multiple.html
  • 原生 <select>multiple,触发区域换成 data-cb-select-field,已选项以标签形式显示
  • 多选时点击选项不会关闭面板,Esc 或点击外部关闭

分组

examples/select/groups.html

使用原生 <optgroup>,搜索时分组标题会随结果一起显示。

结构

html
<div class="relative" data-cb-select data-placeholder="请选择">
  <!-- 1. 选项与取值:视觉隐藏的原生 select,参与表单提交与 required 校验 -->
  <select name="country" required class="sr-only" tabindex="-1" aria-hidden="true">
    <option value=""></option>
    <option value="SG" data-keywords="Singapore xinjiapo">新加坡 (SG)</option>
  </select>

  <!-- 2. 触发按钮:外观与输入框一致 -->
  <button id="country" type="button" data-cb-select-trigger class="flex h-11 w-full … aria-expanded:border-brand">
    <span data-cb-select-value class="min-w-0 flex-1 truncate data-placeholder:text-muted-foreground"></span>
    <svg>chevron-down</svg>
  </button>

  <!-- 3. 面板:搜索框 + 选项列表(选项由脚本渲染) -->
  <div data-cb-select-panel hidden class="absolute top-full left-0 z-40 mt-1 w-full … data-[side=top]:bottom-full">
    <div class="relative border-b border-border">
      <input type="text" data-cb-select-search placeholder="搜索" class="…" />
    </div>
    <ul data-cb-select-list class="max-h-64 overflow-y-auto p-1"></ul>
  </div>
</div>
部件 / 属性说明
<select>选项的唯一来源。value="" 的选项视为「未选择」,不出现在列表里
data-cb-select-value单选时显示所选文字;未选择时带 data-placeholder 属性
data-cb-select-field + data-cb-select-chips + data-cb-select-placeholder多选的触发区域
data-cb-select-search搜索框,省略则不显示搜索
data-cb-select-clear清除按钮(可选)
data-placeholder未选择时的文案,默认取 value="" 选项的文字
data-text-empty没有搜索结果时的文案,默认「无匹配结果」
data-remove-label多选标签移除按钮的读屏前缀,英文页面填 Remove
data-keywords(写在 option 上)额外的搜索关键词

面板默认显示在下方,下方空间不足时自动翻到上方。

取值与事件

值始终保存在原生 <select> 上,读取方式和普通下拉完全一样:

js
const el = document.querySelector('#country-select')

el.querySelector('select').value              // 单选
new FormData(form).getAll('markets')          // 多选

el.addEventListener('cb:select-change', ({ detail }) => {
  detail.value   // 单选:'SG';多选:['HK', 'SG']
  detail.labels  // ['新加坡 (SG)']
})

CbtisUI.setSelectValue(el, 'HK')              // JS 设置(多选传数组)

选择后原生 <select> 会派发 inputchange 事件,Vue 的 v-model 可直接绑定在 <select> 上。业务代码修改了 <select> 的值或选项后,派发一次 change 或调用 CbtisUI.init(el),界面即会更新。

键盘

按键结果
在触发按钮上按 / / Enter / Space打开面板,焦点进入搜索框
在触发按钮上直接打字打开面板并把字符带入搜索框
移动高亮选项(跳过禁用项)
Enter选择高亮选项(多选为切换)
Esc关闭并把焦点还给触发按钮
Tab / 点击外部关闭

使用建议

推荐

  • 选项 2–4 个且需要让用户一眼看到全部时,用选择卡片代替
  • 国家、币种、行业等长列表务必补充 data-keywords(英文名、代码),中英文用户都能搜到
  • 选项文案:「新加坡 (SG)」——名称在前,代码在后

避免

  • 默认选中一个「看起来合理」的值,导致用户漏选
  • 多选超过 5 个标签时仍平铺显示——考虑改用独立的列表页或弹窗

无障碍

  • 触发按钮:aria-haspopup="listbox" + aria-expanded;搜索框:role="combobox" + aria-activedescendant;列表:role="listbox"(多选加 aria-multiselectable)。以上都由脚本设置
  • <label for> 指向触发按钮;没有可见标签时给触发按钮加 aria-label
  • 表单提交时如果 required 校验失败,脚本会把 aria-invalid="true" 加到触发按钮上,错误样式随之显示

与 v2 的差异

v2 现状规范
单选使用原生 <select>,外观随系统变化,不能搜索自定义下拉,支持搜索,值仍保存在原生 select
多选(MultiSelect.vue)不能搜索;移除按钮是嵌在 <button> 里的 span[role=button]与单选统一;移除按钮与触发按钮平级
多选箭头使用字符 lucide chevron-down