aria-selected="true"仅在role="tablist"/"grid"/"tree"等复合角色上下文中有效,需JS同步更新属性与样式,并显式设置所有非选中项为aria-selected="false"。

aria-selected="true" 必须配合 role="tablist" / "grid" / "tree" 等复合角色使用
单独给任意元素加 aria-selected="true" 不会触发屏幕阅读器播报“已选中”,也不会被 AT(辅助技术)识别为有效状态。它只在特定 WAI-ARIA 复合组件上下文中才有语义意义。
常见误用:给普通 <div> 或 <code><button></button> 直接加 aria-selected,却不设 role —— 这属于无效标注,AT 会忽略该属性。
-
role="tablist"+aria-selected用于标签页(tabs),每个tab应有role="tab" -
role="grid"+aria-selected用于可选中表格(如数据表格行选中),子项需为role="row"和role="gridcell" -
role="tree"+aria-selected用于树形控件,节点需为role="treeitem"
选中态必须由 JS 动态控制,不能仅靠 CSS 类切换
无障碍要求的是状态同步:视觉变化(如高亮)和 ARIA 状态必须严格一致。仅切换 .is-selected 类但不更新 aria-selected,会导致屏幕阅读器读取错误状态。
正确做法是用 JS 同时操作 DOM 属性和样式:
立即学习“前端免费学习笔记(深入)”;
tabEl.setAttribute('aria-selected', 'true');
tabEl.classList.add('tab--selected');
// 切换前务必清除旧选中项
oldTabEl.setAttribute('aria-selected', 'false');
oldTabEl.classList.remove('tab--selected');
- 不要用
aria-selected做纯样式钩子(例如 CSS 中写[aria-selected="true"] { background: #007bff; }是 OK 的,但前提是 JS 确实同步设置了该属性) - 避免用
aria-selected替代原生checked或selected—— 单选/复选框、<select></select>应优先用原生语义
键盘焦点与 aria-selected 必须分离管理
aria-selected="true" 描述的是“逻辑选中”,不是“当前聚焦”。用户用 Tab 键移动焦点时,焦点可能落在未选中的项上;按方向键切换选中项时,焦点也未必跟随移动 —— 这两者是正交的。
- 焦点(
tabindex、focus())决定键盘操作目标 -
aria-selected决定“哪个项被用户视为当前激活/选定” - 典型场景:在
role="tablist"中,应保持一个 tab 永远有焦点(用tabindex="0"),而aria-selected="true"只出现在当前激活的 tab 上,二者可不同步(例如按 ←→ 切换选中态但不移焦)
React/Vue 中容易漏掉 aria-selected 的条件重置
框架组件化渲染时,常因条件渲染或 key 变化导致 aria-selected 属性残留或丢失。比如用 v-for 或 {items.map()} 渲染 tab 列表,但没在每次 render 时显式设置所有项的 aria-selected 值。
错误写法(只设选中项,未设其他项为 false):
{tabs.map(tab => (
<button
role="tab"
{...tab.id === activeId ? {'aria-selected': 'true'} : {}}
>
{tab.label}
</button>
))}
正确写法(显式控制每个项):
{tabs.map(tab => (
<button
role="tab"
aria-selected={tab.id === activeId ? 'true' : 'false'}
tabIndex={tab.id === activeId ? 0 : -1}
>
{tab.label}
</button>
))}
- 服务端渲染(SSR)或静态生成时,初始 HTML 中的
aria-selected也必须准确,不能依赖 JS 注入后才补全 - 测试时可用 Chrome DevTools 的 Accessibility 面板直接查看
aria-selected是否实时存在且值正确
aria-selected="false"」—— 很多人只记得设 true,却让其他项留空,而空值 ≠ false,AT 会将其视为“未定义状态”。


















