tabindex 应仅用 0 和 -1:0 使非原生元素按 DOM 顺序参与焦点流(需配 role、keydown、:focus-visible),-1 仅用于 JS 主动聚焦;禁用正数,避免破坏自然 Tab 流。

tabindex 只该用 0 和 -1,其他值基本等于埋雷。 正整数(如 tabindex="1")会打乱自然 Tab 流,tabindex="-1" 不是“隐藏”,而是“留给 JS 聚焦的入口”;tabindex="0" 也不是“加了就能用”,它只让非原生元素按 DOM 顺序进焦点流——前提是配齐 role、keydown 和 :focus-visible。
哪些元素必须加 tabindex="0",哪些绝对不能加
加 tabindex="0" 的唯一合理场景,是给**本不可聚焦但需键盘操作的容器**声明“我愿意参与 Tab 流”。典型例子:
-
<div role="button">展开</div>—— 没它,键盘用户 Tab 到这里就跳过 -
<h3 role="tab">配置项</h3>—— 仅当整个标题需作为 Tab 键可停靠点时才加 - 自定义折叠面板标题、树节点容器等有明确交互意图的非表单元素
以下情况严禁加 tabindex="0":
- 原生可聚焦元素:
<button>、<a href>、<input>、<select>、<textarea>—— 它们默认就在 Tab 流里,加了反而可能干扰 React hydration 或 SSR 焦点恢复 - 纯展示容器:
<div class="avatar"><img></div>、<span class="icon"></span>—— 键盘多停一次却无事可做,污染屏幕阅读器播报 - 已包裹可聚焦子元素的卡片或列表项 —— 会造成双重焦点停靠,用户按一次 Tab 却触发两次停顿
tabindex="-1" 的唯一合法用途:让 JS 主动聚焦
tabindex="-1" 不是“禁用”,也不是“视觉隐藏”,它的作用非常窄:让一个元素**不被 Tab 键碰到,但能被 .focus() 主动聚焦**。常见误用:
立即学习“前端免费学习笔记(深入)”;
- 给整个模态框根容器设
tabindex="-1",结果.focus()落在空 div 上,用户按 Tab 仍跳到页面其他地方 - 目标元素还没挂载(比如异步加载的
<input>)就调.focus(),DOM 找不到,静默失败 - 聚焦后元素被
overflow: hidden或transform遮挡,没补element.scrollIntoView({ block: 'nearest' }),用户看不见焦点在哪
正确做法:
- 模态框内第一个可操作项(如确认按钮)在 HTML 中就带
tabindex="-1" - JS 打开模态框后,立刻执行
confirmBtn.focus() - 关闭前记录
document.activeElement,关完立即回焦
为什么永远不要写 tabindex="1" 或更高正数
写 tabindex="1" 不会让它变成“第一个被 Tab 到的元素”。浏览器实际行为是:所有正数 tabindex 元素会被集中塞到 Tab 流最前面,再按数值升序排,然后才是 tabindex="0" 和原生可聚焦元素。后果包括:
- 多个
tabindex="1"元素中,浏览器只认第一个,其余无效 - React/Vue 动态插入新组件后,硬编码的正数无法重算,焦点跳转错乱
- iOS Safari 直接无视大部分正数
tabindex,还可能触发控制台警告 - 屏幕阅读器把第一个
tabindex="1"当作逻辑起点 —— 如果它是页脚的“导出”按钮,用户一进页面就听到“导出”,主编辑区上下文全丢
真正要控制顺序,靠的是 HTML 源码位置:导航栏放顶部,它就第一个被 Tab 到;表单字段从上到下写,Tab 流就自然向下走。
加了 tabindex="0" 还不能用?缺这三样就等于白加
只加 tabindex="0" 是半成品。键盘用户 Tab 到那里后,还必须能操作、能感知、能理解:
-
必须同步加
role:比如<div role="button">,否则屏幕阅读器读作“段落”或“无名容器” -
必须监听
keydown:对Enter和Space做响应;Space要e.preventDefault(),否则页面滚动 -
CSS 必须补
:focus-visible:如果清除了outline,得加:focus-visible { outline: 2px solid #007bff; },否则焦点不可见
最容易被忽略的是:移动端 Safari 在触摸模式下默认不支持 tabindex="0" 的非表单元素焦点 —— 这不是 bug,是平台策略。真要覆盖,得依赖辅助功能开关开启“全键盘控制”,而非强行 hack。



















