原生<dialog>默认不渲染,必须用showModal()或show()激活;仅设open属性可初始显示,但showModal()才启用遮罩、ESC关闭和焦点锁定。
原生 <dialog> 不是“写完就能弹”,必须用 showModal() 触发,否则页面上根本看不到它。
<dialog> 却没显示?<dialog> 默认 display: none,连 DOM 渲染都跳过,不是“隐藏”而是“不参与布局”。光写标签、加 class、设 style 都没用。
open 属性:<dialog open></dialog>(但多数场景不该这么做)dialog.showModal()(模态)或 dialog.show()(非模态)dialog.hidden = true/false 或 dialog.style.display —— 这会绕过原生焦点和 backdrop 逻辑,导致 Tab 键失效、Esc 不响应showModal();旧版 Safari、IE 完全不识别该元素这是规范行为,不是 bug。showModal() 创建的 ::backdrop 默认不可点击,浏览器不会自动绑定关闭逻辑。
dialog.addEventListener('click', e => { if (e.target === dialog) dialog.close(); });
e.target 在 backdrop 上可能始终是 <body>,需 fallback 到坐标判断(如 e.clientX < dialog.getBoundingClientRect().left)dialog 设 pointer-events: none —— 这会让 showModal() 的焦点锁定彻底失效oncancel="event.preventDefault()" 即可因为 <form> 在 <dialog> 内默认会触发表单提交,刷新整个页面 —— dialog.close() 根本没机会执行。
立即学习“前端免费学习笔记(深入)”;
event.preventDefault()
submit 回调里,而不是靠按钮的 onclick
button type="button",避免意外触发 form 行为dialog.returnValue 做表单返回值处理,它只在 close(value) 显式传参时有效,且不适用于所有交互路径<dialog>?不能直接靠 useState 控制 open 属性渲染——React 的 diff 机制会销毁/重建节点,导致 showModal() 状态丢失、焦点归还失效。
useRef 持有对 <dialog> 元素的引用ref.current.showModal() 或 ref.current.close()
useEffect 里反复调用 showModal(),避免 Safari 下报错 “The element is already active”ref.current?.hasAttribute('open') 再决定是否聚焦,防止 SSR 渲染错乱最常被忽略的其实是焦点管理:如果 <dialog> 里第一个子元素是 <h3> 或 <div tabindex="-1">,showModal() 会静默失败,Tab 键直接跳出模态框。确保第一个可聚焦元素存在且可用,比写十行 CSS 都关键。