下拉选择 Select
从一组选项中选择一个或多个。单选、多选使用同一个组件,都支持搜索,外观在所有浏览器和系统上一致。
单选
examples/select/single.html
- 可以输入中文、英文或选项值搜索;在每个选项的
data-keywords里补充英文名、拼音、别名,搜索会一并匹配 - 可清除:加一个
data-cb-select-clear按钮(有值时自动显示),文字区域data-cb-select-value加pr-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> 会派发 input 与 change 事件,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 |