tabindex仅合法值为0和-1:tabindex="0"仅用于需键盘访问的非原生元素(如),须配role、keydown监听和:focus-visible;tabindex="-1"专供JS主动聚焦;正整数必须删除,否则破坏焦点流与可访问性。

tabindex 不是用来“排号”或“美化导航”的装饰属性,它是键盘可访问性的底层开关——关了,键盘用户根本进不来;设错值,焦点流直接断裂。
tabindex="0" 该加在哪些元素上才真正有用
只加在本不该可聚焦、但业务又需要键盘进入的容器上,比如 <div role="button">、<code><h3 role="tab"></h3>、自定义折叠面板标题。原生 <button></button>、<a href></a>、<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></textarea>——全靠它。
- 常见错误包括:给整个
tabpanel容器设tabindex="-1",结果.focus()落在空容器上,用户按 Tab 还是跳到页面其他地方 - 目标元素还没渲染完成(比如异步加载的表单字段)就调
.focus(),DOM 找不到,静默失败 - 聚焦后元素被
overflow: hidden或position: absolute遮挡,没配element.scrollIntoView({ block: 'nearest' }),用户看不见焦点在哪 - 移动端 Safari 在未触发用户手势前,
.focus()对非原生元素会静默失败
为什么永远不要用 tabindex="1"
写 tabindex="1" 不会让它变成“第一个被 Tab 到的元素”,只会把它塞进所有正数里排最小——但多个 tabindex="1" 仍按 DOM 顺序走,和没设一样。更糟的是,一旦混入 tabindex="0" 的链接或按钮,Tab 流变成“正数 → 0 值 → 其他”,完全失控。
将 Markdown 文章转换为微信公众号兼容的纯 HTML 格式。当用户要求"转成微信格式"、"生成公众号文章 HTML"、"排版到微信草稿箱"、"微信粘贴格式"时触发。输出带内联样式的纯 HTML,微信编辑器可直接渲染,无需额外适配。支持标题、段落、列表、粗体、行内代码、表格、引用块、代码块、配图的完整转换。
立即学习“前端免费学习笔记(深入)”;
- 移动端 Safari 直接无视大部分
tabindex="0",tabindex="1"更无效,还可能触发警告 - React/Vue 动态插入新组件后,硬编码的正数无法重算,焦点跳转错乱
- 屏幕阅读器把第一个
tabindex="1"当作逻辑起点,如果它是页脚的“导出按钮”,用户一进页面就听到“导出”,主编辑区上下文全丢 - Grid/Flex 布局中,正整数
tabindex与视觉顺序无关,只放大 DOM 顺序错位的风险
滚动容器 + tabindex 的交互陷阱
给一个带 overflow-y: auto 的 <div> 加了 <code>tabindex="0",本意是让它可聚焦以便键盘导航,但你会发现:聚焦后按方向键无法滚动内容。
- 原因在于:可聚焦 ≠ 可滚动。浏览器只对原生可滚动元素(如
<textarea></textarea>、<iframe></iframe>)默认启用方向键滚动;对普通<div tabindex="0">,方向键无响应 <li>解决办法是手动监听 <code>keydown,判断ArrowUp/ArrowDown并调用element.scrollTop - 或者改用
<textarea readonly></textarea>替代(需隐藏边框和 resize 控制器) - 更稳妥的做法:避免让非语义容器承担滚动 + 焦点双重职责;优先用
<section aria-label=""></section>等语义化结构替代
最易被忽略的点是:tabindex 值本身不携带语义,也不触发任何行为——它只是“开门”,门后有没有路、路通不通、路上有没有标识,全靠 role、keydown、:focus-visible 和 DOM 顺序共同决定。


















