Declarative Shadow DOM的HTML写法是<template shadowroot="open">或<template shadowroot="closed">,必须作为宿主元素的第一个子节点,内部可含<style>和<slot>等,浏览器自动将其内容挂载为Shadow Root。

Declarative Shadow DOM的HTML写法长什么样
Declarative Shadow DOM不是JavaScript API,而是直接在HTML里用<template shadowroot="open">或<template shadowroot="closed">声明Shadow Root。浏览器解析到这个<template>时,会自动将其内容挂载为Shadow Root,无需调用attachShadow()。
关键点:必须是<template>元素,且必须带shadowroot属性;该<template>必须是对应宿主元素的**第一个子节点**(紧贴宿主标签内部),否则会被忽略。
-
<div id="my-el"><template shadowroot="open"><style>span{color:red}</style><span>Hello</span></template></div>—— 合法,<template>是<div>的第一个子节点 -
<div id="my-el"><span>before</span><template shadowroot="open">...</template></div>—— 无效,前面有其他节点 -
<div id="my-el"><template shadowroot="open"><slot></slot></template></div>—— 支持<slot>,但注意:slot内容来自light DOM,不是template内部文本
为什么shadowroot属性值只能是open或closed
它直接映射到Shadow Root的mode,和JS中el.attachShadow({mode: 'open'})行为一致。区别在于:declarative方式创建的closed Shadow Root,其shadowRoot属性在JS中返回null,且无法通过getElementById等API访问内部节点——这是设计使然,不是bug。
注意:shadowroot="closed"在服务端直出时有效,但后续JS无法通过el.shadowRoot拿到引用,调试和动态操作受限。生产环境慎用closed,除非明确需要强封装。
立即学习“前端免费学习笔记(深入)”;
- 服务端渲染(SSR)场景下,
open更实用,前端可补JS逻辑 -
closed对SEO和无障碍支持无额外增益,反而增加调试成本 - 没有
shadowroot="auto"或其它值,仅接受open/closed字符串字面量
常见错误:模板内容没生效或报错Failed to execute 'attachShadow' on 'Element'
这个错误其实不会在Declarative Shadow DOM中出现——因为它不调用attachShadow()。如果你看到这个报错,说明你同时写了Declarative模板又手动调用了attachShadow(),触发了冲突:浏览器已自动挂载,再调用会失败。
- 检查是否重复初始化:服务端输出了
<template shadowroot>,客户端JS又执行el.attachShadow() - 确保
<template>未被JS移除或重排(例如Vue/React的DOM diff可能误删它) - Chrome 115+支持,Firefox 120+支持,Safari 17.4+支持;旧版Safari或Edge 113前版本直接忽略该语法,回退为light DOM(需降级处理)
- 不能用
<script>标签包裹在<template>内执行——template内容不执行脚本,只作结构挂载
和JS版Shadow DOM共存时要注意什么
Declarative Shadow DOM本质是“预挂载”,一旦解析完成,宿主元素就有了shadowRoot。此时再调用el.attachShadow()会失败,而读取el.shadowRoot能正常拿到引用(open模式下)。
真正容易被忽略的是:Declarative Shadow DOM的内容在HTML解析阶段就确定了,后续JS修改template内部HTML无效——它只读一次,之后template本身不再参与更新。
- 想动态更新Shadow DOM内容?别改
<template>,改el.shadowRoot下的节点 - 服务端直出+客户端hydration时,确保hydrate逻辑不覆盖已有
shadowRoot - 使用
innerHTML设置宿主元素内容会清空已挂载的Shadow Root——因为整个子节点被重置,包括那个<template>



















