References

Beginner-friendly references for web development, with live, editable examples.

The HTML shadowrootserializable attribute

Attribute Updated
In short

The HTML shadowrootserializable attribute marks a declarative shadow root, created with <template shadowrootmode>, as serializable. Calling getHTML({ serializableShadowRoots: true }) on the host then includes that shadow tree in the returned HTML, which is off by default.

Overview

The shadowrootserializable attribute lets a declarative shadow root be written back out as HTML. It is a boolean attribute on a <template> that also has shadowrootmode, and it sets the new shadow root's serializable flag to true.

Serialization is opt-in twice. The shadow root has to be serializable, and the caller has to ask with element.getHTML({ serializableShadowRoots: true }). When both hold, the output contains a <template shadowrootmode="open" shadowrootserializable=""> wrapper around the shadow content, markup that the HTML parser reads as a declarative shadow root.

innerHTML and outerHTML never include shadow roots, whatever the flag says, and getHTML() with no options leaves them out too. Its shadowRoots option can include specific shadow roots even when they are not marked serializable.

The flag is set once, when the parser attaches the shadow root, and ShadowRoot.serializable is read-only afterward. MDN's compatibility data lists the attribute in Chrome and Edge 125 and Safari 18. Firefox 128 supports the matching serializable option of attachShadow(), but the table lists no Firefox support for the declarative attribute.

Syntax

<my-card>
  <template shadowrootmode="open" shadowrootserializable>
    <p>Shadow content</p>
  </template>
</my-card>

Values

Value
A boolean attribute: present or absent.

Example

Live example
<div id="a"><template shadowrootmode="open" shadowrootserializable><b>Serializable</b></template></div>
<div id="b"><template shadowrootmode="open"><b>Not serializable</b></template></div>
<ul>
  <li>getHTML() of #a: <code id="a-out"></code></li>
  <li>getHTML() of #b: <code id="b-out"></code></li>
  <li>innerHTML of #a: <code id="a-inner"></code></li>
</ul>
<script>
  const opts = { serializableShadowRoots: true };
  const a = document.getElementById('a');
  const b = document.getElementById('b');
  document.getElementById('a-out').textContent = a.getHTML(opts) || '(empty string)';
  document.getElementById('b-out').textContent = b.getHTML(opts) || '(empty string)';
  document.getElementById('a-inner').textContent = a.innerHTML || '(empty string)';
</script>

Best practices

  • Add shadowrootserializable only to shadow roots you really need to read back as HTML, such as components you save or snapshot.
  • Leave closed shadow roots non-serializable unless you mean to expose them, because getHTML() serializes a serializable root even when its mode is closed.
  • Pass { serializableShadowRoots: true } explicitly, since getHTML() without options returns only the light DOM.
  • Use the shadowRoots option of getHTML() when you need one specific shadow root, instead of marking every instance serializable.
  • Keep shadowrootmode on the same template, because without a valid mode no shadow root is created and the attribute does nothing.

Frequently asked questions

What does shadowrootserializable do?
The shadowrootserializable attribute marks a declarative shadow root as serializable. The getHTML() method then includes that shadow tree when serializableShadowRoots is true.
Why does innerHTML not include my shadow DOM?
Neither innerHTML nor outerHTML ever serializes shadow roots, even ones created with shadowrootserializable. Call getHTML() with serializableShadowRoots set to true instead.
Does shadowrootserializable work with closed shadow roots?
Yes, getHTML() still includes a closed shadow root that carries shadowrootserializable. The serialized template then has shadowrootmode set to closed.
Is shadowrootserializable supported in all browsers?
Not yet, according to MDN's compatibility data for shadowrootserializable. It lists Chrome and Edge 125 and Safari 18, while Firefox is listed only for the serializable option of attachShadow().
How do I make a shadow root serializable without the template attribute?
Pass serializable: true to attachShadow(), as in host.attachShadow({ mode: 'open', serializable: true }). That is the JavaScript equivalent of shadowrootserializable.
Can I change shadowrootserializable after the page loads?
No, the serializable flag is fixed when the shadow root is created. The template that carried shadowrootserializable is consumed by the parser, and ShadowRoot.serializable is read-only.