启用 delegatesfocus 可使外层表单容器点击或 tab 时自动将焦点委托至 shadow dom 内首个可聚焦元素,提升键盘导航连贯性;必须设为 true 的场景是 shadow dom 封装的表单组件需支持连续 tab 导航,否则焦点会在容器边界中断。

启用 delegatesFocus 能让外层表单容器在被点击或按 Tab 键时,自动把焦点“穿透”进 Shadow DOM 内部第一个可聚焦元素,显著改善嵌套表单的键盘导航连贯性。它不改变 DOM 结构,只调整焦点委托行为,对屏幕阅读器和键盘用户尤其关键。
什么时候必须设为 true
当你的表单组件(如自定义下拉、日期选择器、带搜索的输入框)封装在 Shadow DOM 中,且用户需要连续按 Tab 键从一个字段跳到下一个时,必须开启 delegatesFocus。否则焦点会在 Shadow 容器边界中断,用户无法进入内部控件。
- 自定义
<my-select></my-select>包含隐藏的<input>和弹出菜单 -
<date-range-picker></date-range-picker>内部有两个<input type="date"> - 富文本工具栏按钮组 + 编辑区域共处一个 Shadow Root
如何正确配置
在 attachShadow 时直接传入参数,不要依赖后续修改 —— delegatesFocus 是只读属性,创建后不可变更:
const host = document.createElement('form-section');
const shadow = host.attachShadow({
mode: 'open',
delegatesFocus: true // ✅ 关键:声明即生效
});
shadow.innerHTML = `
<label>姓名:<input name="name"></label>
<label>邮箱:<input name="email"></label>
`;
document.body.appendChild(host);
注意:若使用 ReactShadow 或类似封装库,需确认其 API 是否透传该参数(例如 <reactshadow delegatesfocus="{true}"></reactshadow>)。
配合 tabindex 与 focusable 元素使用
delegatesFocus 只会把焦点委托给 Shadow 内部第一个可聚焦且未被禁用的元素。因此要确保:
- 内部至少有一个元素满足:有
tabindex(≥0)、是原生可聚焦标签(input、button、select等),或设置了contenteditable="true" - 避免所有输入都设
tabindex="-1"或disabled,否则委托会失败,焦点停留在 host 元素上 - 如需控制委托目标,可在内部用
slot暴露占位,或在connectedCallback中主动input.focus()
与可访问性(a11y)协同
单纯开启 delegatesFocus 不够,还需配套语义化标记:
- 用
<label for="id"></label>或包裹关系关联标签与输入,确保屏幕阅读器能播报 - Shadow 内部的
<input>应保留id,外部<label></label>可通过for属性跨 Shadow 引用(现代浏览器已支持) - 若组件含多个逻辑字段(如地址组件含省市区三级下拉),建议用
role="group"包裹,并为每个子控件提供明确的aria-label











