角色 复合控件
listbox
将元素标记为可选选项的列表。简单的单选场景请使用 <select>——原生元素提供适合移动端的选择器与完整的键盘支持。仅在需要自定义样式、带自定义渲染的多选功能,或与组合框配合使用时,才使用 role="listbox"。
使用时机
尽可能使用 <select>(单选)或 <select multiple>(多选)。原生元素提供完整的交互模型,包括符合平台规范的键盘处理。
以下情况适合使用 role="listbox":
- 列表框作为自定义组合框的弹出层。
- 需要富选项内容(图标、辅助文字),而
<select>无法渲染。 - 需要带自定义勾选样式的多选功能。
- 构建穿梭框或可过滤的选择器。
子元素必须为 role="option"(允许使用 role="group" 作为分组的中间层包装)。多选列表框需设置 aria-multiselectable="true"。
键盘与焦点规范
参见 APG 列表框模式:
- Tab 将焦点移入列表框;再次 Tab 移出。列表框内部,焦点保持在容器上,“活动”选项通过
aria-activedescendant追踪。 - 上下方向键移动活动选项。
- Home / End 跳转到第一个 / 最后一个选项。
- 单选:每次按方向键同时选中活动选项。
- 多选:Space 切换活动选项的选中状态;Shift+方向键扩展连续区域;Ctrl/Cmd+A 全选。
- 输入预测:输入字母跳转到下一个以该字母开头的选项。
常见错误
- 将 DOM 焦点移至每个选项,而非使用
aria-activedescendant。这会导致输入预测和组合框集成失效。 role="option"子元素缺少id属性——aria-activedescendant无法引用它们。- 多选列表框未设置
aria-multiselectable="true"。屏幕阅读器会将其宣读为单选。 - 列表框拥有位于 DOM 其他位置的选项,却未使用
aria-owns明确关联关系。 - 对只读静态列表使用
role="listbox"。那应该是role="list"而非 listbox——listbox 隐含交互性。
示例
<label id="topicsLabel">选择您的主题</label>
<ul
role="listbox"
aria-labelledby="topicsLabel"
aria-multiselectable="true"
tabindex="0"
aria-activedescendant="topic-1"
>
<li id="topic-1" role="option" aria-selected="true">无障碍</li>
<li id="topic-2" role="option" aria-selected="false">辅助技术</li>
<li id="topic-3" role="option" aria-selected="true">标准规范</li>
</ul>