Declarative shadow DOM
Write SSR-friendly shadow DOM with <template shadowrootmode>.
What is declarative shadow DOM?
Imperative shadow DOM calls element.attachShadow() in JS, so server-rendered HTML has no shadow DOM and content is missing until JS loads.
Declarative shadow DOM moves this into HTML: anything inside a <template shadowrootmode="open"> becomes a shadow root at parse time. No JS is needed; it's SSR-friendly and the page ships with shadow DOM on first paint.
shadowrootmode syntax
The rule: place a <template> inside a custom element and set its shadowrootmode property to "open" or "closed". At parse time the browser turns the template into a shadow root and removes the template; the shadow root remains.
open lets outside code reach the root via element.shadowRoot; closed blocks it. Most components use open for easier testing and accessibility.
Exercise Write a profile-card with declarative shadow DOM
Write a <profile-card> element. Inside:
- Open and close a
<template shadowrootmode="open"> - Inside the template, an
<h2>with non-empty title content - Inside the template, a
<slot name="name"> - Outside the template but inside profile-card, an
<h2 slot="name">with non-empty name content - End with the
</profile-card>closing tag
Show example solution
<profile-card>
<template shadowrootmode="open">
<h2>Profile card</h2>
<slot name="avatar"></slot>
<slot name="name"></slot>
<slot name="bio"></slot>
</template>
<img slot="avatar" src="/user/alex/avatar.png" alt="Alex Morgan avatar">
<h2 slot="name">Alex Morgan</h2>
<p slot="bio">Product designer, lives in London.</p>
</profile-card>
Test yourself
-
What's the main advantage of declarative shadow DOM over imperative attachShadow?
<template shadowrootmode="open">...</template>- Less code to write
- It works inside HTML during SSR
- It runs faster
- It needs no CSS encapsulation
Show answer
It works inside HTML during SSR — Correct. Declarative shadow DOM lives in HTML, so it's SSR-friendly and doesn't wait for JS.
-
Complete the declarative shadow DOM template
<template ____="open"><slot name="avatar"></slot></template>Show answer
<template shadowrootmode="open"><slot name="avatar"></slot></template> -
Match each approach to its feature
- shadowrootmode
- In HTML
- attachShadow
- In JS
- SSR friendly
- Declarative
- Waits for JS
- Imperative