dialog.showModal() 不会自动聚焦取消按钮,需在调用后用 setTimeout 或 requestAnimationFrame 延迟执行 cancelBtn.focus();autofocus 和 tabindex 无效,因浏览器焦点管理会覆盖且 tabindex="-1" 仅支持脚本聚焦。

dialog.showModal() 打开时默认聚焦到取消按钮的实现方式
直接调用 showModal() 不会自动聚焦任何元素,浏览器默认聚焦行为取决于 DOM 顺序和可聚焦元素类型,但通常不会聚焦到你期望的“取消按钮”。必须手动干预焦点逻辑。
为什么不能靠 tabindex 或 autofocus 属性自动生效
autofocus 在 <dialog> 内部对非 input/button 元素无效;即使加了 autofocus,showModal() 的内部焦点管理也会覆盖它。且 tabindex="-1" 本身不触发聚焦,只是让元素可被脚本聚焦。
-
<button autofocus>Cancel</button>在showModal()后可能被忽略(尤其在 Safari 和旧版 Chrome) -
tabindex="0"只影响 Tab 键顺序,不等于打开即聚焦 - 部分浏览器会在 modal 打开后将焦点移到
<dialog>自身(变成不可见焦点),导致键盘操作失效
正确做法:showModal() 后立即调用 focus()
必须等 showModal() 完成、dialog 渲染并进入可聚焦状态后再执行 .focus()。推荐使用 setTimeout(..., 0) 或 requestAnimationFrame 避免同步时机问题。
<dialog id="myDialog">
<p>确认删除?</p>
<button id="cancelBtn">取消</button>
<button id="confirmBtn">确定</button>
</dialog>
<script>
const dialog = document.getElementById('myDialog');
const cancelBtn = document.getElementById('cancelBtn');
dialog.showModal();
// 确保 dialog 已激活且可聚焦
setTimeout(() => {
cancelBtn.focus();
}, 0);
</script>
- 不用
dialog.addEventListener('shown', ...)——<dialog>没有shown事件 - 避免在
showModal()前就调用cancelBtn.focus(),此时 dialog 还未渲染,会失败 - 如果取消按钮是
<button type="button">,确保它没有disabled,否则.focus()无效果
补充:键盘 Esc 关闭时保持焦点逻辑一致
用户按 Esc 关闭 dialog 后,焦点会回到触发它的元素(通常是打开 dialog 的按钮)。如果你希望关闭后也聚焦某个特定元素(比如原取消按钮对应的上层控件),需监听 close 事件手动处理:
立即学习“前端免费学习笔记(深入)”;
<pre class="brush:php;toolbar:false;">dialog.addEventListener('close', () => {
// 例如:恢复到页面顶部的搜索框
document.getElementById('searchInput').focus();
});
dialog.close() 触发 <code>close事件,但showModal()不触发open事件- 不要依赖
onclose属性写法,优先用addEventListener - 若取消按钮绑定了
dialog.close(),它本身不是焦点陷阱(trap)的一部分,需自行保证焦点不意外跳到 body 外



















