Testing

Declarative Shadow DOM: Browser Support, Syntax, Limitations

Declarative Shadow DOM works in Chrome 111+, Edge 111+, Firefox 123+, Safari 16.4+, Opera 97+, and Samsung Internet 22+. Browser support, syntax, and limits.

Author

Prince Dewani

May 6, 2026

Declarative Shadow DOM is a WHATWG HTML feature that lets a <template shadowrootmode> element create a shadow root directly from server-rendered markup, without JavaScript. It works in Chrome 111+, Edge 111+, Firefox 123+, Safari 16.4+ on macOS and iOS, Opera 97+, and Samsung Internet 22+, while Internet Explorer never added support.

This guide covers what Declarative Shadow DOM is, the browsers that support it, the shadowrootmode syntax, the production use cases, the known limitations, and how to feature-detect support.

What is Declarative Shadow DOM?

Declarative Shadow DOM is a WHATWG HTML feature that turns a <template> element with a shadowrootmode attribute into the shadow root of its parent during HTML parsing. It moves shadow root creation out of JavaScript and into static markup, so server-rendered web components attach their styles and slots before any script runs.

Which browsers does Declarative Shadow DOM support?

Declarative Shadow DOM is supported by every major modern browser engine: Chromium, Gecko, and WebKit. Internet Explorer is the only mainstream browser that never added support.

Loading browser compatibility data...

Declarative Shadow DOM compatibility in Chrome

Chrome supports Declarative Shadow DOM from Chrome 111 on Windows, macOS, Linux, ChromeOS, and Android. Chrome 90 to 110 shipped the earlier non-standard shadowroot attribute, which Chrome 111 renamed to the standard shadowrootmode. Chrome 4 to 89 did not support it.

Declarative Shadow DOM compatibility in Edge

Edge supports Declarative Shadow DOM from Edge 111 on Windows, macOS, Linux, and Android. Edge 91 to 110 supported the legacy shadowroot attribute. Edge 12 to 90 did not support it.

Declarative Shadow DOM compatibility in Firefox

Firefox supports Declarative Shadow DOM from Firefox 123 on Windows, macOS, Linux, and Android. Firefox 2 to 122 did not parse the shadowrootmode attribute and treated the template as inert markup.

Declarative Shadow DOM compatibility in Safari

Safari supports Declarative Shadow DOM from Safari 16.4 on macOS Ventura and later, and from Safari 16.4 on iOS and iPadOS. Earlier Safari versions on macOS and iOS do not support it. WebKit landed the implementation in Safari Technology Preview before the stable Safari 16.4 release.

Declarative Shadow DOM compatibility in Opera

Opera supports Declarative Shadow DOM from Opera 97 on desktop and from Opera Mobile 80 on Android. Opera 77 to 96 supported the legacy shadowroot attribute that tracked Chrome 90 to 110. Opera 9 to 76 did not support it.

Declarative Shadow DOM compatibility in Samsung Internet

Samsung Internet supports Declarative Shadow DOM from Samsung Internet 22 on Android. Samsung Internet 16 to 21 supported the legacy shadowroot attribute, and earlier versions did not support it at all.

Declarative Shadow DOM compatibility in Android Browser

The standalone Android Browser added support in its modern Chromium-based builds. Chrome on Android 111 and later parses the shadowrootmode attribute the same way as desktop Chrome.

Declarative Shadow DOM compatibility in Internet Explorer

Internet Explorer never supported Declarative Shadow DOM. Microsoft has retired Internet Explorer; ship Edge 111 or later for users still on legacy Microsoft browsers.

Note

Note: Declarative Shadow DOM behavior shifts between Chrome 111, Firefox 123, and Safari 16.4. Test your server-rendered web components on real browsers and OS with TestMu AI. Try TestMu AI free!

What is the syntax of Declarative Shadow DOM?

A declarative shadow root is a <template> element with a shadowrootmode attribute set to either open or closed. The HTML parser detects the attribute, removes the template from the DOM, and attaches its content as the shadow root of the parent element.

<!-- Server-rendered HTML, no JavaScript needed -->
<user-card>
  <template shadowrootmode="open">
    <style>
      span { color: rebeccapurple; font-weight: 600; }
    </style>
    <span>Hello from the shadow root</span>
    <slot></slot>
  </template>
  <p>This light DOM child gets slotted in.</p>
</user-card>

Three rules follow from this design. First, only the parser builds shadow roots this way; setting shadowrootmode on a template after page load does nothing. Second, each parent element accepts only one declarative shadow root. Third, standard insertion APIs like innerHTML and DOMParser ignore the attribute, so use setHTMLUnsafe() or parseHTMLUnsafe() when you need to parse trusted markup at runtime.

What are the use cases of Declarative Shadow DOM?

Declarative Shadow DOM is the missing piece for server-rendered web components. It lets you ship encapsulated UI without paying the JavaScript-first cost that earlier shadow DOM required.

  • Server-side rendering of web components: Frameworks like Lit SSR, Enhance, and WebC serialize shadow roots into HTML so the browser shows styled components on first paint.
  • No-JavaScript baselines: Static site generators emit fully styled components that work even when JavaScript is blocked or fails to load.
  • Better Core Web Vitals: Removing the JavaScript handshake required to attach shadow roots cuts Largest Contentful Paint and removes the flash of unstyled content for component-heavy pages.
  • Streaming HTML: The parser attaches the shadow root the moment it sees the opening template tag, so progressively streamed HTML renders without buffering the whole document.
  • Progressive hydration: A custom element can read its own shadow root through ElementInternals.shadowRoot and decide whether to wire up behavior or skip the work.
...

What are the known limitations of Declarative Shadow DOM?

Declarative Shadow DOM is well supported, but the design imposes several constraints that catch teams off guard during their first SSR rollout.

  • Parser-only construction: A template marked shadowrootmode only becomes a shadow root during initial HTML parsing. The same markup inserted via innerHTML or insertAdjacentHTML is treated as a regular template.
  • One shadow root per element: Adding a second declarative template to the same parent throws a parse error. Each host element accepts exactly one declarative shadow root.
  • No adopted stylesheets: Constructable CSSStyleSheet objects passed through adoptedStyleSheets cannot be serialized, so they do not survive the round trip from server to declarative shadow root.
  • Strict parser entry points: Only setHTMLUnsafe() and parseHTMLUnsafe() honor shadowrootmode at runtime; the safer counterparts strip it to prevent cross-site scripting through user-supplied HTML.
  • Older browser fallback: Browsers below Chrome 111, Firefox 123, or Safari 16.4 ignore the template entirely, so you need either a polyfill or a script that walks template[shadowrootmode] and calls attachShadow manually.

In my experience, the parser-only rule is the limitation that bites teams hardest: a component that hydrates correctly on the first request silently breaks the moment a partial swap reuses the same template through innerHTML, and the bug surfaces only after the first client-side navigation.

...

How do you check if a browser supports Declarative Shadow DOM?

The cleanest feature test reads HTMLTemplateElement.prototype for the shadowRootMode property. Browsers that parse the standard attribute expose it on the prototype; browsers that do not, return false.

function hasDeclarativeShadowDOM() {
  return Object.prototype.hasOwnProperty.call(
    HTMLTemplateElement.prototype,
    'shadowRootMode'
  );
}

if (hasDeclarativeShadowDOM()) {
  console.log('Declarative Shadow DOM is supported');
} else {
  console.log('Falling back to JavaScript-attached shadow roots');
}

Run this snippet in the DevTools console of any browser. A supported browser logs Declarative Shadow DOM is supported; an unsupported browser falls back to attaching shadow roots via JavaScript. Avoid sniffing the user agent string, since both Chromium and WebKit forks ship with their own version timelines.

Citations

All Declarative Shadow DOM version numbers and platform notes in this guide come from these primary sources:

Author

Prince Dewani is a Community Contributor at TestMu AI, where he manages content strategies around software testing, QA, and test automation. He is certified in Selenium, Cypress, Playwright, Appium, Automation Testing, and KaneAI. Prince has also presented academic research at the international conference PBCON-01. He further specializes in on-page SEO, bridging marketing with core testing technologies. On LinkedIn, he is followed by 4,300+ QA engineers, developers, DevOps experts, tech leaders, and AI-focused practitioners in the global testing community.

Open in ChatGPT Icon

Open in ChatGPT

Open in Claude Icon

Open in Claude

Open in Perplexity Icon

Open in Perplexity

Open in Grok Icon

Open in Grok

Open in Gemini AI Icon

Open in Gemini AI

Copied to Clipboard!
...

3000+ Browsers. One Platform.

See exactly how your site performs everywhere.

Try it free
...

Write Tests in Plain English with KaneAI

Create, debug, and evolve tests using natural language.

Try for free

Frequently asked questions

Did you find this page helpful?

More Related Hubs

TestMu AI forEnterprise

Get access to solutions built on Enterprise
grade security, privacy, & compliance

  • Advanced access controls
  • Advanced data retention rules
  • Advanced Local Testing
  • Premium Support options
  • Early access to beta features
  • Private Slack Channel
  • Unlimited Manual Accessibility DevTools Tests