Shadow DOM
Shadow DOM is a web standard that offers component style and markup encapsulation. It is a critical piece of the Web Components story. It allows you to attach a hidden, separated DOM tree to an element.
1. Why do we need it?
In the standard DOM, everything is global.
- CSS Leaks: A style defined for
h1affects everyh1on the page. - ID Conflicts:
id="container"must be unique across the entire page. - Fragility: JavaScript can accidentally select elements inside a widget and break it.
Shadow DOM solves this by creating a "scoped" subtree.
2. Terminology
- Shadow Host: The regular DOM node that the shadow DOM is attached to.
- Shadow Tree: The DOM tree inside the Shadow DOM.
- Shadow Boundary: The place where the shadow DOM ends, and the regular DOM begins.
- Shadow Root: The root node of the shadow tree.
3. Creating Shadow DOM
You create a shadow root using element.attachShadow().
const host = document.querySelector('#host');
const shadowRoot = host.attachShadow({ mode: 'open' });
shadowRoot.innerHTML = `
<style>
p { color: red; } /* Only affects paragraphs inside this shadow root */
</style>
<p>I am in the shadows!</p>
`;
4. Encapsulation
CSS Isolation
Styles defined inside the Shadow DOM do not leak out. Styles defined outside do not leak in (mostly).
- Exception: Inheritable properties (like
color,font-family) still trickle down from the host.
DOM Isolation
document.querySelector('p') will not find the paragraph inside the shadow root. To access it, you must go through the shadow root: host.shadowRoot.querySelector('p').
5. Open vs. Closed Mode
When attaching a shadow root, you specify a mode.
open: You can access the shadow root usingelement.shadowRoot.const root = host.attachShadow({ mode: 'open' }); console.log(host.shadowRoot); // Returns the ShadowRoot objectclosed:element.shadowRootreturnsnull. This makes it harder (but not impossible) for outside JS to access the internal DOM.const root = host.attachShadow({ mode: 'closed' }); console.log(host.shadowRoot); // nullNote: Closed mode is rarely used because it prevents even your own code from easily accessing the root, and it doesn't offer true security.
6. Event Retargeting
When an event bubbles up from the Shadow DOM to the Light DOM (the regular page), its target is adjusted to look like it came from the Shadow Host.
- Inside Shadow DOM: Target is the specific button clicked.
- Outside Shadow DOM: Target is the
<my-component>host element.
This preserves encapsulation; the outside world doesn't need to know about the internal structure.
programming/javascript/vanilla/javascript programming/javascript/vanilla/web-components programming/javascript/vanilla/dom-manipulation