delegatesfocus 是 shadow dom 的选项,解决宿主不可聚焦时点击无法进入内部可聚焦元素的问题;需在 attachshadow({ delegatesfocus: true }) 中启用,仅支持 open 模式,且依赖宿主 tabindex 和内部元素可聚焦性。

delegatesFocus 是什么,它解决什么问题
当 Shadow DOM 内部有可聚焦元素(比如 <input>、<button></button>),而宿主元素(host)本身不可聚焦时,用户点击宿主往往不会触发焦点进入——浏览器默认不把焦点“穿透”进 shadow。设为 delegatesFocus: true 后,点击宿主会自动将焦点委托给 shadow 内第一个可聚焦的后代,同时保持 document.activeElement 指向宿主(而非内部元素),这是实现“表层聚焦语义”的关键。
如何正确启用 delegatesFocus
必须在调用 attachShadow() 时传入该选项,创建后无法动态修改:
const host = document.querySelector('#my-host');
host.attachShadow({ mode: 'open', delegatesFocus: true });
- 只支持
mode: 'open','closed'下会被忽略 - 若 shadow 已存在(比如被框架提前挂载),重复调用
attachShadow()会抛出DOMException: Failed to execute 'attachShadow' on 'Element': This element already has a shadow root - 不要试图用
shadowRoot.delegatesFocus = true—— 这个属性是只读的,赋值无效
为什么点了宿主没反应?常见失效原因
即使启用了 delegatesFocus,焦点委托也可能静默失败:
系统化 Debug 与根因调查框架:通过调查‑分析‑假设‑验证四步追踪根本原因,只进行根因修复,适用于 Bug 调试、异常行为分析、服务报错排查,提供可验证的结论。
- shadow 内没有可聚焦元素:检查是否有
tabindex="-1"或disabled阻断了可聚焦性 - 内部元素被
pointer-events: none或visibility: hidden遮挡,导致点击事件没落到可聚焦节点上 - 宿主元素本身有
tabindex="-1"或inert,浏览器认为它不该参与焦点流 - 使用了
slot且内容投影后结构变化,实际可聚焦节点不在 shadow 的直接子树中(例如插槽内容被移入另一个 shadow)
与 focus() 方法和 tabindex 的配合要点
delegatesFocus 只影响鼠标点击/触摸行为,不影响脚本调用 .focus()。但二者可以共存:
- 手动调用
host.focus()也会触发委托,前提是 host 有tabindex(哪怕为0或-1) - 如果 host 没设
tabindex,即使delegatesFocus: true,键盘 Tab 也无法聚焦它——委托只响应主动点击,不改变可 tab 焦点顺序 - 想让宿主可被 Tab 到,必须显式加
tabindex="0";若只想响应点击委托,tabindex="-1"就够用
这个选项真正起效的地方很窄:它只在用户点击宿主、且宿主本不可聚焦时,悄悄把焦点“转交”出去,同时维持语义归属。漏掉 tabindex 或误判可聚焦节点位置,就等于白配。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!










