是,但仅限点击宿主元素时自动聚焦Shadow内首个可聚焦元素;不改变Tab顺序,不修复focus()调用,不穿透多层Shadow,与键盘导航无关,误用可能导致选区清除。

delegatesFocus 设为 true 后,焦点真的会自动跳进 Shadow 内部吗
会,但仅限于“点击宿主元素”这个动作。比如你有一个 <my-input> 自定义元素,它内部用 attachShadow({ mode: 'open', delegatesFocus: true }) 创建了 shadow root,并在其中放了一个原生 <input>,那么用户点击 <my-input> 的任意空白区域(非 input 本身),焦点就会自动落到那个内部 <input> 上——前提是该 <input> 是第一个可聚焦元素(tabindex="-1" 以外的、有 disabled 属性的不算)。
常见错误是以为 delegatesFocus 能接管所有焦点行为:它不改变 Tab 键顺序,不修复 focus() 调用失败,也不影响 document.activeElement 的返回值逻辑。它只响应一次性的点击触发。
- 必须确保 shadow 内部存在至少一个可聚焦元素(
<button>、<input>、tabindex="0"的<div>等) - 若内部多个元素都可聚焦,只委托给
shadowRoot.querySelector('[tabindex], button, input, select, textarea, [contenteditable]')找到的第一个 - 如果内部元素被
display: none或visibility: hidden,它会被跳过
为什么在多层嵌套 Shadow 中 delegatesFocus 容易失效
因为 delegatesFocus 不具备“穿透性”。假设有三层结构:<outer> → <middle> → <inner>,每层都用了 attachShadow,即使全部设为 delegatesFocus: true,点击 <outer> 也只会把焦点委托给 <middle> 的第一个可聚焦元素,而不会继续往下钻到 <inner> 的 input 里。
根本原因在于:焦点委托只发生在“宿主元素被点击”和“其直接 shadow root”之间,浏览器不会递归遍历嵌套 shadow tree。
- 解决方法不是堆
delegatesFocus,而是控制哪一层真正承载可聚焦内容——通常只在最内层组件启用,外层保持delegatesFocus: false - 若必须由外层接收点击并最终聚焦到深层 input,需手动调用
shadowRoot.querySelector('...').focus(),此时delegatesFocus反而可能干扰(比如触发两次 focus 事件) - 注意
focus({ preventScroll: true })的调用时机:应在focusin事件后、或setTimeout微任务中执行,避免被浏览器默认行为覆盖
delegatesFocus 与键盘导航(Tab)完全无关
这是最容易误解的一点。delegatesFocus 只影响鼠标点击行为,对键盘 Tab 流完全没作用。Shadow DOM 默认就支持 Tab 导航进入其内部(只要内部有可聚焦元素),无需任何配置。
OpenClaw Gateway 重启性能分析工具:分析重启速度、定位启动慢原因、生成性能报告、诊断启动问题。支持 Windows (PowerShell) 与 Linux (Bash)。触发场景:分析 gateway 重启、检查启动时间、生成报告、诊断异常。
如果你发现按 Tab 键无法进入 shadow 内部,问题一定出在别处:
- shadow 内部没有可聚焦元素(比如只有
<span>和<div>,且没加tabindex) - 宿主元素本身被设了
tabindex="-1"或aria-hidden="true",导致它从 Tab 顺序中被剔除 - 父级容器用了
inert属性,或 CSSpointer-events: none(虽然不影响 Tab,但常被误配) - Chrome 128+ 中,若 shadow host 是
<div>且未设tabindex,部分版本会跳过它——显式加tabindex="0"最稳妥
真实场景中 delegatesFocus 的典型误用
在富文本编辑器插件或代码高亮工具栏这类需要“宿主选区持久化”的场景下,强行开启 delegatesFocus 可能加剧体验断裂。因为点击 toolbar 按钮时,不仅焦点进去了,宿主页面的 document.getSelection() 也会被清空——这和 Shadow DOM 的设计有关,不是 bug,是当前规范下的既定行为。
资料已明确验证:无论你怎么拦截 mousedown、focusin,都无法阻止选区清除。所以当业务强依赖“保持光标位置/选中文本”,delegatesFocus 不是优化项,而是风险源。
此时更务实的选择是降级为 <iframe>,或者改用 light DOM + CSS-in-JS / scoped class 命名来规避样式冲突,放弃 Shadow DOM 的封装换回选区稳定性。

















