tabindex="0"应仅加在需键盘聚焦的非原生可聚焦元素上,如<div role="button">、<h3 role="tab">等,须配role属性、keydown监听及focus样式;tabindex="-1"仅用于程序主动聚焦;禁用tabindex="1"等正数。

tabindex="0"该加在哪些元素上
只加在本不该可聚焦、但业务又需要键盘进入的容器上,比如 <div role="button">、<h3 role="tab">、自定义折叠面板标题。原生 <button>、<a href>、<input> 本来就进 Tab 流,加了反而可能干扰 SSR hydration 或 React 焦点管理。
常见错误是给纯展示文本或图标容器加 tabindex="0",结果屏幕阅读器多读一遍“无意义 div”,键盘用户多停一次却无事可做。
- 必须同步加
role属性(如role="button"),否则辅助技术读作“段落”或“无名容器” - 必须监听
keydown,对Enter和Space做响应;Space要e.preventDefault(),否则页面滚动 - CSS 中若移除了 outline,得补
:focus-visible { outline: 2px solid #007bff; },否则焦点不可见
tabindex="-1"不是隐藏开关,是聚焦入口
tabindex="-1" 的唯一合法用途:让一个元素**不能被 Tab 键碰到,但能被 .focus() 主动聚焦**。模态框打开后聚焦第一个按钮、选项卡切换后聚焦内容区首项、代码编辑器激活时聚焦 <textarea>——全靠它。
常见错误包括:
立即学习“前端免费学习笔记(深入)”;
- 给整个
tabpanel容器设tabindex="-1",结果.focus()落在空容器上,用户按 Tab 还是跳到页面其他地方 - 目标元素还没渲染完成(比如异步加载的表单字段)就调
.focus(),DOM 找不到,静默失败 - 聚焦后元素被
overflow: hidden或position: absolute遮挡,没配element.scrollIntoView({ block: 'nearest' }),用户看不见焦点在哪
为什么永远不要用 tabindex="1"
写 tabindex="1" 不会让它变成“第一个被 Tab 到的元素”,只会把它塞进所有正数里排最小——但多个 tabindex="1" 仍按 DOM 顺序走,和没设一样。更糟的是,一旦混入 tabindex="0" 的链接或按钮,Tab 流变成“正数 → 0 值 → 其他”,完全失控。
真实影响包括:
- 移动端 Safari 直接无视大部分
tabindex="0",tabindex="1"更无效,还可能触发警告 - React/Vue 动态插入新组件后,硬编码的正数无法重算,焦点跳转错乱
- 屏幕阅读器把第一个
tabindex="1"当作逻辑起点,如果它是页脚的“导出按钮”,用户一进页面就听到“导出”,主编辑区上下文全丢
焦点流转依赖两层机制,tabindex只管一层
tabindex 只控制 Tab 键在线性序列中的起点和终点,不负责方向键行为。箭头键(ArrowLeft/ArrowRight)、Home/End 的循环切换,必须靠 JS 拦截并手动管理焦点——tabindex 对它完全无效。
这意味着:
- 选项卡组件里,Tab 键进出组件靠
tabindex="0"和tabindex="-1",但左右切换标签页必须监听keydown并调.focus() - 工具栏按钮组若用 Flex/Grid 视觉重排,Tab 键仍按 DOM 顺序走,别指望
tabindex能对齐视觉流 - focus({ preventScroll: true }) 在 Safari 中不支持,传对象参数会静默失败,真实项目建议先检测支持性



















