基础单选
可搜索 · 分组
华北
华东
华南
多选 · 最多 3 个
富选项 · 固定面板宽
<div class="demo-col"> <p class="chart-cap" style="margin:0 0 6px">基础单选</p> <div class="icen-select" data-icen-select style="width:100%;max-width:280px"> <button class="icen-select-trigger icen-pressable icen-focus-ring" type="button" aria-haspopup="listbox" aria-expanded="false"> <span class="icen-select-value is-empty">选择一种水果</span> </button> <div class="icen-select-panel" hidden> <button class="icen-select-option" type="button" data-icen-value="apple">苹果</button> <button class="icen-select-option" type="button" data-icen-value="banana">香蕉</button> <button class="icen-select-option" type="button" data-icen-value="orange">橙子</button> <button class="icen-select-option" type="button" data-icen-value="grape">葡萄</button> <button class="icen-select-option" type="button" data-icen-value="mango">芒果</button> </div> <input type="hidden" data-icen-select-value name="fruit" /> </div> <p class="chart-cap" style="margin:14px 0 6px">可搜索 · 分组</p> <div class="icen-select" data-icen-select data-icen-select-search style="width:100%;max-width:280px"> <button class="icen-select-trigger icen-pressable icen-focus-ring" type="button" aria-haspopup="listbox" aria-expanded="false"> <span class="icen-select-value is-empty">搜索城市…</span> </button> <div class="icen-select-panel" hidden> <div class="icen-select-group"> <p class="icen-select-group-label">华北</p> <button class="icen-select-option" type="button" data-icen-value="bj">北京</button> <button class="icen-select-option" type="button" data-icen-value="tj">天津</button> </div> <div class="icen-select-group"> <p class="icen-select-group-label">华东</p> <button class="icen-select-option" type="button" data-icen-value="sh">上海</button> <button class="icen-select-option" type="button" data-icen-value="hz">杭州</button> <button class="icen-select-option" type="button" data-icen-value="nj">南京</button> </div> <div class="icen-select-group"> <p class="icen-select-group-label">华南</p> <button class="icen-select-option" type="button" data-icen-value="gz">广州</button> <button class="icen-select-option" type="button" data-icen-value="sz">深圳</button> </div> </div> <input type="hidden" data-icen-select-value name="city" /> </div> <p class="chart-cap" style="margin:14px 0 6px">多选 · 最多 3 个</p> <div class="icen-select" data-icen-select data-icen-select-multiple data-icen-select-max="3" data-icen-select-placeholder="选择标签(最多 3 个)" style="width:100%;max-width:280px"> <button class="icen-select-trigger icen-pressable icen-focus-ring" type="button" aria-haspopup="listbox" aria-expanded="false"> <span class="icen-select-value is-empty">选择标签(最多 3 个)</span> </button> <button class="icen-select-clear" type="button" aria-label="清除全部" hidden><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" width="16" height="16" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round" focusable="false" class="icen-symbol" aria-hidden="true"><path d="M6 6l8 8M14 6l-8 8"></path></svg></button> <div class="icen-select-panel" hidden> <button class="icen-select-option" type="button" data-icen-value="ts">TypeScript</button> <button class="icen-select-option" type="button" data-icen-value="react">React</button> <button class="icen-select-option" type="button" data-icen-value="vue">Vue</button> <button class="icen-select-option" type="button" data-icen-value="svelte">Svelte</button> <button class="icen-select-option" type="button" data-icen-value="rust">Rust</button> <button class="icen-select-option" type="button" data-icen-value="go">Go</button> </div> <input type="hidden" data-icen-select-value name="tags" /> </div> <p class="chart-cap" style="margin:14px 0 6px">富选项 · 固定面板宽</p> <div class="icen-select" data-icen-select data-icen-panel-width="216" style="width:100%;max-width:216px"> <button class="icen-select-trigger icen-pressable icen-focus-ring" type="button" aria-haspopup="listbox" aria-expanded="false"> <span class="icen-select-value is-empty">选择色彩预设</span> </button> <div class="icen-select-panel" hidden> <button class="icen-select-option" type="button" data-icen-value="modern"><span class="icen-select-swatch" aria-hidden="true"><i style="background:#f5f6f8"></i><i style="background:#087bf5"></i><i style="background:#58758f"></i></span>现代</button> <button class="icen-select-option" type="button" data-icen-value="dongyun"><span class="icen-select-swatch" aria-hidden="true"><i style="background:#f4f1e9"></i><i style="background:#477668"></i><i style="background:#85724d"></i></span>东韵</button> <button class="icen-select-option" type="button" data-icen-value="jugou"><span class="icen-select-swatch" aria-hidden="true"><i style="background:#edece6"></i><i style="background:#b53c2d"></i><i style="background:#596d75"></i></span>巨构</button> <button class="icen-select-option" type="button" data-icen-value="piano"><span class="icen-select-swatch" aria-hidden="true"><i style="background:#f5f3ed"></i><i style="background:#94713f"></i><i style="background:#657386"></i></span>钢琴</button> <button class="icen-select-option" type="button" data-icen-value="monet"><span class="icen-select-swatch" aria-hidden="true"><i style="background:#f4f7f4"></i><i style="background:#2b675c"></i><i style="background:#667c8a"></i></span>莫奈</button> <button class="icen-select-option" type="button" data-icen-value="vangogh"><span class="icen-select-swatch" aria-hidden="true"><i style="background:#f8f3e4"></i><i style="background:#275ea0"></i><i style="background:#a0711e"></i></span>梵高</button> </div> <input type="hidden" data-icen-select-value name="preset" /> </div></div>
特性
- 形态:缺省单选;
data-icen-select-search可搜索(支持分组icen-select-group);data-icen-select-multiple多选 +data-icen-select-max上限 - 键盘:↑↓ 移动、Enter 选中、Esc / 外点关闭,支持首字定位
- 富选项:
icen-select-option内可写任意 HTML(色卡 / 图标 / 多行) - 面板尺寸:全库统一 PanelSizing 契约——
data-icen-panel-width固定宽 /-min/-max夹取 /-max-height高度上限(默认 240) - 数据:选中值同步隐藏 input(
name直接进表单);子节点与文案变更自动同步,手动改类后调refreshSelect - 事件:选中变化派
icen:select-change——detail{ value, values, label }:单选value为选中值、values为单元素数组;多选values为全部选中值、value取首个;清空(.icen-select-clear或全部取消)后为{ value: '', values: [], label: '' }。隐藏 input 同步值并派原生change(双通道,表单框架用)
触发器与输入框同视觉,表单里混排不跳脱;多选的移除按钮原生可聚焦,键盘可直接操作。
接口
- 初始化
initSelect()(kit 一行入口可直接命名导入)- 导出
-
refreshSelect - 事件
-
icen:select-changedetail 契约见IcenEventMap - 类型
dist/behaviors/select.d.mts(随 npm 包发布,含全部 JSDoc 约束)
安装
bun add @icen.ai/ui pnpm add @icen.ai/ui npm install @icen.ai/ui yarn add @icen.ai/ui 一行引入该组件(CSS 与 behavior 自动带上,无需关心内部 CSS 文件名):
import { initSelect } from '@icen.ai/ui/kit/select';initSelect();
也可以用脚手架直接打印引入行:
bunx --bun @icen.ai/ui add select
Astro 项目注意:kit 入口里的 CSS import 在页面 <script> 里会被 Astro 的 client bundle 摇掉——请改在布局 frontmatter 里引 CSS(import '@icen.ai/ui/components/select.css';),JS 行为仍可走 kit。Vite SPA / webpack 项目无此问题。
用法
import { initSelect, refreshSelect } from '@icen.ai/ui/kit/select';const destroy = initSelect(root);// 子节点、标签文字、原生 disabled 改动会自动同步。// 手动修改 is-selected 类后,可明确请求一次静默同步:refreshSelect(root);// 页面或组件卸载时:destroy();// 事件:icen:select-change(bubbles + composed,detail 全型登记 IcenEventMap)// detail { value, values, label }:// 单选 value = 选中值,values = [value],label = 选项可见文本// 多选 values = 全部选中值,value = 首个选中值,label = 选中项文本 ', ' 连接// 清空 (.icen-select-clear 或逐项取消)→ { value: '', values: [], label: '' }// 隐藏 input(data-icen-select-value)同步值(多选逗号连接)并派原生 change —— 双通道:// icen 事件给行为层,原生 change 给表单框架。import { onIcen } from '@icen.ai/ui';onIcen('icen:select-change', (e) => console.log(e.detail.value, e.detail.values, e.detail.label));<!-- 基础单选 --><div class="icen-select" data-icen-select>…</div><!-- 可搜索(带分组) --><div class="icen-select" data-icen-select data-icen-select-search>…</div><!-- 多选 + 上限 --><div class="icen-select" data-icen-select data-icen-select-multiple data-icen-select-max="3">…</div><!-- 多选:trigger 同级加 .icen-select-clear;选中标签与触发按钮为同级,移除按钮原生可聚焦 --><!-- 富选项:.select-option 内可直接写任意 HTML(色卡 / 图标 / 多行) --><!-- 面板尺寸(全库统一 PanelSizing 契约,浮层组件通用): data-icen-panel-width="216" 固定宽(最高优先) data-icen-panel-min / -max 以 trigger 宽为基准夹取 data-icen-panel-max-height="320" 高度上限(select 默认 240) -->