tabindex仅控制元素能否聚焦、是否入Tab流及相对位置;0值最安全,-1用于编程聚焦,禁用正整数;需配合role、focus样式、inert等确保可访问性。
tabindex 不是用来给元素“编号排序”的开关,它只决定三件事:元素能否被聚焦、是否进入 Tab 流、在流中相对于 DOM 顺序的位置——值的正负零直接对应这三种行为,错用正整数会破坏键盘导航逻辑,尤其在动态组件中极易引发焦点丢失或跳转混乱。
tabindex="0" 是最常用也最安全的启用方式
给
、
或自定义控件加
tabindex="0"
,能让它按 HTML 源码顺序自然加入 Tab 流。但它不是“开箱即用”的交互元素:
不自动响应空格/回车:必须手动监听
keydown
并判断
event.key === 'Enter'
或
' '
语义缺失:屏幕阅读器不会识别它是按钮,需同步加
role="button"
(或其他匹配角色)
无焦点样式 = 键盘用户失明:务必配
:focus-visible
或至少
:focus
CSS 规则
原生可聚焦元素(如
、
)无需加
tabindex="0"
,加了反而多余
tabindex="-1" 是编程聚焦的唯一可靠入口
设为 -1 后,元素无法通过 Tab 键到达,但能用
.focus()
主动聚焦——这是模态框、选项卡、下拉菜单等动态组件的焦点控制核心:
模态框打开时,立即对第一个可操作元素(如确认按钮)调用
.focus()
,前提是该元素有
tabindex="-1"
Accordion 展开后,焦点应移到新暴露的首项,而不是留在触发按钮上
关闭弹层后,焦点应回退到触发它的元素(比如原“编辑”按钮),可用
document.activeElement
记录或传参保存
tabindex="-1"
不等于视觉隐藏:仅设它,元素仍可能被 Tab 到(如果 CSS 用
opacity: 0
或
position: absolute; left: -9999px
隐藏),此时需配合
inert
属性或显式移除
tabindex
绝对不要用正整数 tabindex(如 1、2、5)
浏览器只看是否 > 0,不严格按数值排序;多个正数时虽按升序排,但一旦漏值(比如只有 1 和 3),2 不会补位,且原生可聚焦元素会被挤到最后,整个 Tab 流就断层了:
立即学习
“
前端免费学习笔记(深入)
”;
组件复用或动态插入内容时,正整数必须全局重算,极易出错
SSR 渲染时客户端与服务端
tabindex
值不一致,会触发 hydration 警告
屏幕阅读器用户依赖文档流逻辑,强行打乱顺序会让其困惑——导航栏在源码顶部,就让它第一个被 Tab 到
禁用的
自动脱离 Tab 流,无需额外设
tabindex="-1"
隐藏/禁用元素的 tabindex 处理要格外小心
不可用(
disabled
)或视觉隐藏(
display: none
/
visibility: hidden
)的元素,即使设了
tabindex
也不会出现在 Tab 流中。但要注意:
aria-hidden="true"
不影响
tabindex
行为,若同时存在,需显式设
tabindex="-1"
或移除
tabindex
仅用
opacity: 0
或
position: absolute; left: -9999px
隐藏的元素,仍可能被 Tab 到,应配合
inert
(现代浏览器支持)或
tabindex="-1"
动态显示/隐藏区域(如折叠面板)切换时,需同步更新
tabindex
和
inert
状态,否则焦点可能落在不可见元素上
真正难的不是写对
tabindex
,而是在组件状态频繁变化时,始终让焦点落在用户预期的位置——这需要把焦点管理当作和数据流一样严肃的状态来维护,而不是加个属性就完事。
