aria-selected 必须用在每个具体的 tab 元素(如 或 )上,而非 tablist 容器;需配合 role="tab" 和 tabindex 使用,并在切换时同步更新状态与焦点。

aria-selected 该用在哪个元素上
它不是给整个 tablist 容器用的,而是必须落在每个具体的 tab 元素(通常是 <button></button> 或 <div role="tab">)上。容器 <code>tablist 只负责用 role="tablist" 声明角色,不设 aria-selected。
常见错误是把 aria-selected="true" 写在 tablist 上,结果屏幕阅读器完全无法识别当前激活项。
- 正确:每个
tab元素单独控制自己的aria-selected值 - 错误:只在
tablist上写一次,或靠 CSS 类名代替 ARIA 状态 - 必须同步更新:切换时,旧
tab的aria-selected要设为"false",新tab设为"true"
为什么不能只靠 class="active" 实现可访问性
CSS 类名对辅助技术完全不可见。即使视觉上高亮了当前选项卡,盲人用户用读屏软件操作时,会感知不到“哪个是当前页签”,也无法通过键盘 →/← 导航后获知焦点落在哪一项——因为缺少语义状态。
aria-selected 是唯一被所有主流读屏器(NVDA、VoiceOver、JAWS)识别的、表示“此 tab 当前被选中”的标准属性。
- 仅用
class="active":读屏器朗读时不会提“已选中”,用户不知道当前在哪 - 仅用
aria-selected但没配role="tab":属性无效,会被忽略 - 必须组合:每个 tab 同时有
role="tab"+aria-selected+tabindex="0"(或由 JS 动态管理焦点)
aria-selected 和 aria-current 的区别
aria-selected 专用于可交互的选择控件,比如 tab、treeitem、option;而 aria-current 是泛用的状态提示,适用于导航链接、时间线节点、面包屑等“只读上下文中的当前位置”。
将调研报告、方案对比、数据分析、需求梳理、会议纪要、设计说明、代码评审、学习笔记等任务产物输出为可在浏览器直接打开的单文件 HTML,替代 Markdown 作为最终交付物。Markdown 在信息密度、视觉清晰度和可分享性上已跟不上 AI 产物的丰富度,HTML 能同时承载排版、表格、SVG 等。
在 tab 场景下硬用 aria-current="page" 不报错,但语义错误——它不表达“用户可点击切换”的交互意图,读屏器可能朗读为“当前页面”,而非“当前标签页”。
- tab 切换控件 → 用
aria-selected - 顶部主导航栏的当前菜单项 → 用
aria-current="page" - 两者混用会导致读屏逻辑混乱,尤其在支持多模式的 AT(如 VoiceOver 的“浏览模式” vs “交互模式”)下表现不一致
JavaScript 更新 aria-selected 时容易漏掉的点
手动写 JS 切换时,光改 DOM 属性还不够,得确保焦点也落到新 tab 上,否则键盘用户按 Tab 会跳过整个 tablist。
示例片段:
// ✅ 正确流程
oldTab.setAttribute('aria-selected', 'false');
newTab.setAttribute('aria-selected', 'true');
newTab.focus(); // 必须!
// 同时要确保 newTab 有 tabindex="0" 或之前已设好可聚焦状态
- 忘记移除旧 tab 的
aria-selected="true",导致多个 true 并存 - 用
className切换时没同步更新 ARIA 属性(纯 CSS 方案不可取) - 动态渲染 tab(如 React/Vue)后未重置 ARIA 状态,初始渲染时所有 tab 都是
aria-selected="false"
最麻烦的是嵌套 tab:外层和内层 tablist 的 aria-selected 必须独立维护,且不能互相干扰。这种结构里,状态管理很容易出错,建议封装成带生命周期钩子的组件逻辑。










