tabindex="0" 是让非原生可聚焦元素(如 div/span)参与键盘导航的必要起点,但需配合 role、keydown 监听和焦点样式才可用;禁用正数 tabindex 和滥用 tabindex="-1" 会破坏焦点流。

tabindex="0" 是让 div/span 可聚焦的唯一起点
直接给 <div> 或 <span> 加 tabindex="0",它才能被 Tab 键导航到——但这只是“开门”,不是“能用”。原生按钮按空格就触发,<div tabindex="0"> 按空格只会滚动页面,没监听、没语义、没样式,等于放了个假门把手。
- 只对非原生可聚焦元素使用:比如
<div>、<span>、<li>、<article> - 绝对不要加在
<button>、<a href>、<input>上——它们默认就在 Tab 流里,加了反而可能破坏 SSR/hydration 焦点同步 - 别用
tabindex="1"或其他正数:它不会让你的元素变成“第一个被 Tab 到的”,只会制造焦点顺序混乱,尤其在 React/Vue 动态渲染中极易失效
加了 tabindex="0" 还不能按 Enter/Space?缺这三样必卡死
键盘用户 Tab 进去之后,发现按回车没反应、按空格页面往下滚、屏幕阅读器读成“段落”——这是典型配套缺失。光有 tabindex="0" 只解决“能不能获得焦点”,不解决“获得焦点后怎么响应”。
- 必须加
role:比如<div role="button" tabindex="0">删除</div>,否则辅助技术不知道这是可操作项 - 必须监听
keydown:捕获Enter和Space,对Space调用e.preventDefault()(否则触发浏览器默认滚动) - 必须提供可见焦点样式:用
:focus-visible最稳妥;若只写:focus,鼠标用户会看到突兀轮廓,建议配合outline: none+ 自定义边框或阴影
表格行 tr 加 tabindex="0" 的坑比想象中多
<tr> 默认不可聚焦,加 tabindex="0" 是让它参与键盘导航的必要操作,但仅此不够——移动端 Safari 完全不支持 <tr> 直接聚焦,DOM 中加了也白加。
- 必须用
tabindex="0",禁用-1或正数:前者进不了 Tab 流,后者打乱顺序 - 操作按钮要放在该行最后一个可聚焦子元素位置:推荐用原生
<button>放在<td>底部,别用<div role="button">模拟 - 移动端兼容方案:额外加一个
position: absolute; opacity: 0;的隐藏<button tabindex="0">,绑定相同逻辑,Safari 才认
什么时候该用 tabindex="-1"?别和 "0" 混用
tabindex="-1" 和 "0" 完全是两套用途:前者是“禁止 Tab 键到达,但允许 JS 主动聚焦”,后者是“让 Tab 键能到达”。混用会导致焦点流断裂,比如模态框关闭后焦点丢失。
立即学习“前端免费学习笔记(深入)”;
- 典型场景:模态框打开后,用
el.focus()聚焦到第一个输入框;表单校验失败后,把焦点移到首个错误字段 - 别给需要键盘导航的交互容器设
-1:比如自定义折叠面板标题、tab 标签页,它们得靠"0"进入 Tab 流 - 检查 DOM 中是否意外存在
tabindex="-1"的原生控件:比如<button tabindex="-1">,这会让它彻底退出 Tab 流,键盘用户永远碰不到
tabindex="0",而是判断这个元素到底“值不值得被 Tab 到”——如果它只是视觉装饰、图标容器、或纯展示性文本,加了只会增加无效停靠点,拖慢键盘用户的操作节奏。



















