0Pricing
HTML Academy · Lesson

attachShadow and Shadow Root

Create an encapsulated shadow tree on a host element.

attachShadow and Shadow Root is a free HTML Academy lesson on CoddyKit — lesson 1 of 4. You can read the complete lesson below for free — then practise it hands-on in the browser with a built-in code editor and a 24/7 AI tutor. It is part of the HTML Academy learning path, one of 4 lessons in the course, and your progress syncs across the web and the CoddyKit app.

What is Shadow DOM?

Shadow DOM gives an element its own isolated DOM tree (the "shadow tree") that does not appear in the page's main DOM. Outer CSS does not leak in, inner CSS does not leak out — perfect encapsulation for components.

Attaching a Shadow Root

Call this.attachShadow({ mode: "open" }) from a custom element's constructor or connectedCallback. The method returns a ShadowRoot, which you can populate just like a regular DOM tree using innerHTML, appendChild, etc.

class MyCard extends HTMLElement {
  constructor() {
    super();
    const shadow = this.attachShadow({ mode: "open" });
    shadow.innerHTML = "<style>p{color:red}</style><p>Hello</p>";
  }
}

Open vs Closed Mode

mode: "open" exposes the shadow tree as element.shadowRoot. mode: "closed" hides it — element.shadowRoot returns null, so outside scripts cannot enter the tree. Closed is rarely useful in practice because the same code that defined the element can keep its own reference anyway.

Style Encapsulation

Styles defined inside the shadow tree (via <style> or adopted stylesheets) apply only inside that shadow tree. CSS selectors in the main document never match shadow descendants, and the shadow's styles never cross out to the document.

The :host Selector

From inside the shadow tree, the host element (the custom element itself) is selected with the special :host pseudo-class. :host(.large) matches when the host has the .large class; :host([disabled]) matches when the host has the disabled attribute.

:host {
  display: block;
  padding: 16px;
  border: 1px solid #ccc;
}
:host([disabled]) {
  opacity: 0.5;
  pointer-events: none;
}

display: block on Custom Elements

Custom elements default to display: inline. Inside the shadow root, apply :host { display: block } so the element behaves like a block-level component. Forgetting this is a common cause of "my width: 100% is being ignored" bugs.

Event Composition

Events that bubble out of the shadow tree are retargeted at the host. A click on an inner button arrives at outer listeners with event.target === host. Use event.composedPath() to see the real internal target if you need it.

composed: true for Custom Events

Custom events dispatched inside the shadow root do not cross the boundary unless you create them with both bubbles: true and composed: true. Without composed, outer listeners on the host never see the event.

Scripts Cannot Leak In

Outside scripts can query the host element but not its shadow descendants. document.querySelector("my-card span") returns nothing if the <span> lives inside the shadow tree. Encapsulation protects internals from accidental coupling.

Declarative Shadow DOM

With <template shadowrootmode="open"> inside an element's HTML, the browser builds the shadow tree at parse time without JavaScript. This makes server-rendered components hydration-friendly because the shadow tree exists before the JS runs.

Performance Considerations

Each shadow root has overhead — extra style scope, extra render layer. Hundreds of shadow roots are fine; tens of thousands may matter. For very high-density UIs (large tables, virtualized lists), profile to confirm shadow DOM costs are acceptable.

Knowledge Check

What does open mode do that closed mode does not?

Summary

attachShadow({ mode: "open" }) creates an isolated DOM subtree where CSS and IDs do not leak in either direction. Style the host with :host, remember display: block, and use composed: true for events that must escape. The shadow tree behaves like a regular DOM otherwise — innerHTML, appendChild, querySelector all work normally inside it.

Frequently asked questions

Is the “attachShadow and Shadow Root” lesson free?

Yes — the full text of “attachShadow and Shadow Root” is free to read here on the web, and the HTML Academy course includes 4 lessons in total. To practise it interactively (a built-in code editor and a 24/7 AI tutor) and unlock the rest of the HTML Academy course, upgrade to CoddyKit PRO.

What will I learn in “attachShadow and Shadow Root”?

Create an encapsulated shadow tree on a host element. You practise HTML Academy with hands-on code you run directly in the browser, and a 24/7 AI tutor answers your questions as you work through the lesson.

Do I need any experience to start HTML Academy?

No prior experience is required. HTML Academy on CoddyKit is structured for beginners through advanced learners; this is — lesson 1 of 4, so you can start here or from the beginning and move at your own pace.

How long does the “attachShadow and Shadow Root” lesson take?

Most CoddyKit lessons take about 5–10 minutes. Each one is bite-sized and interactive, so you make steady progress and pick up exactly where you left off across the web and the app.

Can I write and run code in this HTML Academy lesson?

Yes. Every HTML Academy lesson includes a built-in code editor, so you write and run real code right in your browser and get instant AI feedback — no local setup required.

All lessons in this course

  1. attachShadow and Shadow Root
  2. Slot Elements for Content Distribution
  3. Scoped Styles Inside Shadow DOM
  4. Part and Exportparts for External Styling
← Back to HTML Academy