Understanding and Using Shadow DOM: Concepts, Features, and Practical Examples
This article explains why Shadow DOM exists, introduces its core concepts and features, and provides step‑by‑step code examples for creating, styling, and defining custom elements with Shadow DOM, while also covering compatibility and best practices for modern frontend development.
This article, originally published in Qiwu Weekly by Liu Guanyu, a senior front‑end engineer at 360, introduces the motivation behind Shadow DOM and its role in Web Components.
It starts by describing common UI needs such as draggable sliders and explains that without encapsulation, HTML and CSS are globally visible, leading to style leakage and event‑handling conflicts.
Shadow DOM is presented as a browser‑provided solution that offers DOM and CSS encapsulation, isolation from external changes, and controlled interaction through a defined API.
Key concepts are listed, including Shadow DOM, Light DOM, Shadow Trees, Shadow Host, Shadow Root, Shadow Boundary, content, distributed nodes, template, and slot, each with a brief definition.
The article then outlines the main features of Shadow DOM: structural encapsulation, style encapsulation (including :host, :host-context, ::content selectors), and the altered JavaScript event capture/bubble model across the Shadow Boundary.
Practical usage is demonstrated with several code snippets:
input type="range" disabled min="20" max="100" defaultValue="30"/>Creating a Shadow DOM programmatically:
const div = document.createElement('div');
const sr = div.attachShadow({mode: 'open'});
sr.innerHTML = '
Hello Shadow DOM
';Styling the host element from inside the shadow tree using the :host selector:
<button class="red">My Button</button>
<script>
var button = document.querySelector('button');
var root = button.createShadowRoot();
root.innerHTML = '<style>' +
':host { text-transform: uppercase; font-size:30px; }' +
'</style>' +
'<content></content>';
</script>Using the ::part() selector to style parts exposed by a component:
<style>
c-e::part(innerspan) { color: red; }
</style>
<template id="c-e-outer-template">
<c-e-inner exportparts="innerspan: textspan"></c-e-inner>
</template>
<template id="c-e-inner-template">
<span part="innerspan">This text will be red</span>
<span part="textspan">This text will not be red</span>
</template>
<script>
let host = document.querySelector('c-e');
let root = host.attachShadow({mode:'open'});
let con = document.getElementById('c-e-inner-template').content.cloneNode(true);
root.appendChild(con);
</script>Defining a custom element that uses Shadow DOM:
class FlagIcon extends HTMLElement {
constructor() { super(); this._countryCode = null; }
static get observedAttributes() { return ['country']; }
attributeChangedCallback(name, oldValue, newValue) { this._countryCode = newValue; this._updateRendering(); }
connectedCallback() { this._updateRendering(); }
disconnectedCallback() { console.log('disconnected!'); }
_updateRendering() { /* implementation omitted */ }
}
customElements.define('flag-icon', FlagIcon);
const flagIcon = new FlagIcon();
flagIcon.country = 'zh';
document.body.appendChild(flagIcon);The component lifecycle (constructor, connectedCallback, disconnectedCallback, attributeChangedCallback) is briefly described.
A compatibility table (image) shows that Shadow DOM V1 is supported in modern browsers as of October 2019.
In conclusion, the article summarizes that Shadow DOM is a standard part of Web Components, encourages readers to follow the latest specifications, and points to further articles for related standards.
References are listed at the end, linking to external tutorials, specifications, and examples.
360 Tech Engineering
Official tech channel of 360, building the most professional technology aggregation platform for the brand.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.