Shadow DOM and Encapsulation
Isolate styles and markup in shadow roots.
Shadow DOM and Encapsulation is a free JavaScript Academy lesson on CoddyKit — lesson 3 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 JavaScript Academy learning path, one of 4 lessons in the course, and your progress syncs across the web and the CoddyKit app.
What Is the Shadow DOM?
The Shadow DOM gives an element a private, encapsulated DOM tree. Markup and styles inside it are isolated from the rest of the page.
- Outside CSS does not leak in.
- Inside CSS does not leak out.
- The internal structure is hidden from normal DOM queries.
attachShadow
You create a shadow tree by calling this.attachShadow({ mode: 'open' }). It returns a shadow root that you populate like a normal node.
class FancyBox extends HTMLElement {
constructor() {
super();
this.attachShadow({ mode: 'open' });
}
}
customElements.define('fancy-box', FancyBox);open vs closed Mode
The mode option controls outside access:
'open'— the root is reachable viaelement.shadowRoot.'closed'—element.shadowRootreturnsnull; only your code holds the reference.
Most components use 'open' for easier debugging.
const root = this.attachShadow({ mode: 'open' });
// Later, from outside:
// myEl.shadowRoot -> the shadow root (open)
// closed mode would give null hereFilling the Shadow Root
Set shadowRoot.innerHTML to build the encapsulated content. This markup is invisible to document.querySelector.
class FancyBox extends HTMLElement {
constructor() {
super();
const root = this.attachShadow({ mode: 'open' });
root.innerHTML = '<p>I live inside the shadow DOM</p>';
}
}
customElements.define('fancy-box', FancyBox);Scoped Styles
A style tag inside the shadow root only affects that root. The same selector outside the component is unaffected, and page styles do not bleed in.
root.innerHTML =
'<style>p { color: rebeccapurple; }</style>' +
'<p>Only this paragraph is purple.</p>';
// A <p> elsewhere on the page is NOT affected.The :host Selector
Inside shadow styles, :host targets the custom element itself (the host of the shadow tree). Use it to style the component's outer box.
root.innerHTML =
'<style>' +
':host { display: block; border: 1px solid gray; }' +
':host(.active) { border-color: green; }' +
'</style>' +
'<slot></slot>';Style Isolation in Action
Encapsulation means component authors and page authors stop fighting over class names. A .title rule inside one component never affects a .title elsewhere.
- No global CSS collisions.
- Simple, generic selectors are safe again.
Querying Inside the Shadow Root
To access internal nodes, query the shadow root, not the document. The shadow root supports the same query methods.
class ToggleButton extends HTMLElement {
constructor() {
super();
const root = this.attachShadow({ mode: 'open' });
root.innerHTML = '<button>Off</button>';
this.btn = root.querySelector('button');
}
}
customElements.define('toggle-button', ToggleButton);Events Cross the Boundary
Many events (like click) bubble out of the shadow DOM but are retargeted so outside listeners see the host element, not the internal node. This preserves encapsulation.
// Outside listener sees event.target as <toggle-button>,
// not the inner <button>.
document.querySelector('toggle-button')
.addEventListener('click', e => {
console.log(e.target.tagName); // TOGGLE-BUTTON
});Inheritable Styles
A few CSS properties (like color and font-family) inherit through the shadow boundary because inheritance flows down the composed tree. You can opt into the page's look by relying on inheritance or by using CSS custom properties.
// :host { color: inherit; }
// CSS custom properties also pierce the boundary:
// :host { color: var(--text-color, black); }When to Use Shadow DOM
Reach for shadow DOM when you need strong style and markup isolation for a reusable widget. Skip it when you want the component to inherit and participate in the page's global styles freely.
Quick Check
Test your understanding of the Shadow DOM.
Recap
You learned about the Shadow DOM:
attachShadow({ mode })creates an isolated tree.'open'exposesshadowRoot;'closed'hides it.- Internal
styletags are scoped;:hoststyles the element itself. - Queries run against the shadow root, not the document.
- Events are retargeted to preserve encapsulation.
Next, we reuse markup with templates and slots.
Frequently asked questions
Is the “Shadow DOM and Encapsulation” lesson free?
Yes — the full text of “Shadow DOM and Encapsulation” is free to read here on the web, and the JavaScript 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 JavaScript Academy course, upgrade to CoddyKit PRO.
What will I learn in “Shadow DOM and Encapsulation”?
Isolate styles and markup in shadow roots. You practise JavaScript 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 JavaScript Academy?
No prior experience is required. JavaScript Academy on CoddyKit is structured for beginners through advanced learners; this is — lesson 3 of 4, so you can start here or from the beginning and move at your own pace.
How long does the “Shadow DOM and Encapsulation” 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 JavaScript Academy lesson?
Yes. Every JavaScript 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
- Defining Custom Elements
- Lifecycle Callbacks
- Shadow DOM and Encapsulation
- Templates and Slots