liveBook · Manning

Shadow DOM

As explained in Web Components in Action

Shadow DOM is a web platform mechanism that attaches an encapsulated DOM subtree to an element and isolates its internal structure and styling from the surrounding document.

A reusable component can look self-contained while its markup remains exposed to the page. A page-level query might select a button inside it, and a global button rule might change its appearance. Shadow DOM gives a component a separate DOM tree, reducing these accidental collisions. It is useful, but optional: a custom element can work without it. section 8.1 section 9.1 section 8.0

Call `attachShadow({mode: 'open'})` on an element to create its shadow root, then put the component’s markup in that root rather than in the element’s `innerHTML`. The element is the shadow host; the root contains the separate tree. The `mode` option is required. section 8.2

Listing 8.2. Using the Shadow DOM in a simple component
connectedCallback() {
   this.attachShadow({mode: 'open'});                       #1
   this.shadowRoot.innerHTML =
   `<div class="inside-component">My Component</div>`       #2
}

The two-line component change: attach an open root, then write markup to `this.shadowRoot`. section 8.2

Try `document.querySelector('.inside-component')` after moving that element into the shadow root. It returns `null`: a query on the document does not enter the separate tree. With an open root, code can deliberately reach it through the host’s `shadowRoot` property and query there. This boundary guards against accidental access, not a determined caller. section 8.2

Two choices affect how you work with that boundary:

  • An open root is available as `host.shadowRoot`. A closed root is not available through that property, so keep the value returned by `attachShadow()` if the component needs it. Closed mode is not a reliable security measure; open mode is generally the more practical choice here. section 8.2 section 8.4
  • A shadow root can be created and populated in a custom element’s constructor. That differs from writing children directly into the host there; initialization in `connectedCallback` remains an option. section 4.2 section 8.2

A stepper beside a globally styled button

Imagine a stepper with two buttons and a number between them. Without Shadow DOM, a page-wide `button` rule can alter the stepper, while styles written for the component can affect the page. Move the stepper’s buttons, span, and styles into a shadow root: its internal rules can now use simple `button` and `span` selectors without colliding with those outside. To style the host itself from inside the root, use `:host`, not the component’s tag name. section 9.1 section 9.2

CSS isolation has a wrinkle: inherited text properties can still affect content inside a shadow root. A `:host { all: initial; }` rule is one demonstrated reset. Inside the separate tree, IDs also become practical for selecting component parts; a slider can map its internal elements from `this.shadowRoot`. section 9.2 section 9.5

Check the browsers you need before relying on the boundary. In the browser-support period described here, Firefox had shipped support, while the new Chromium-backed Edge was still in preview; IE would not gain native support. ShadyDOM can help with DOM access, but reproducing CSS isolation with ShadyCSS takes more work. Another fallback is to render into the host when `attachShadow` is unavailable and switch from `:host` to ordinary host selectors. That fallback gives up shadow isolation, so its CSS needs care. section 10.3 section 12.1

How Web Components in Action covers it

How deep it goes
Works through root creation, access modes, CSS isolation, constructor timing, and compatibility fallbacks; treats closed mode as impractical rather than secure.
Examples
Uses a date input’s hidden UI, an exposed component query, a styled stepper, and a slider conversion.
What it assumes
Assumes familiarity with HTML, CSS selectors, DOM queries, and custom elements; defines the shadow host and root while building an example.
What you can do after
Build it from scratch with `attachShadow`, scope internal DOM and CSS, and choose a fallback when native support is unavailable.
How it connects
Connects Shadow DOM to custom elements, encapsulation, slots, CSS inheritance, and lifecycle callbacks.

Also explained in

Compare how 2 books explain Shadow DOM →

Related concepts

This explainer was generated by Manning's knowledge graph from the text of Web Components in Action. The section links point to the parts of the book it draws on.