One of the main benefits of using shadow DOM is style isolation. To understand what this means, let’s assume that we want to create a custom progress bar component. We can use two nested divs to display bars and another DIV to display text to display percentages, as follows:

<style> .progress { position: relative; border: solid 1px; width: 100px; height: 1rem; } .progress > .bar { background: red; height: 100%; } .progress > .label { position: absolute; top: 0; width: 100%; text-align: center; The font - size: 0.8 rem; } </style> <template id="progress-bar-template"> <div class="progress"> <div class="bar"></div> <div class="label">0%</div> </div> </template> <script> function createProgressBar() { var fragment = document.getElementById('progress-bar-template').content.cloneNode(true); var progressBar = fragment.querySelector('div'); progressBar.updateProgress = function (newPercentage) { var ps = newPercentage + '%' this.querySelector('.label').textContent = ps this.querySelector('.bar').style.width = ps } return progressBar; } var p = createProgressBar() document.body.appendChild(p) p.updateProgress(22) </script>Copy the code

Note the use of template elements:

  1. It allows authors to include HTML fragments that can later be instantiated by cloning the content
  2. Template elements can appear anywhere in the document (for example, between table and TR elements)
  3. The content in the template element is lazy and does not run scripts or load images and other types of child resources.

The problem with this progress bar implementation is that its two internal divs are freely accessible to the user, and its style rules are not limited to the progress bar. For example, the style rules defined for the progress bar will be applied to the content outside the progress bar with a class named Progress:

<section class="project">
    <p class="progress">Pending an approval</p>
</section>
Copy the code

Similarly, style rules defined for other elements can override rules in the progress bar:

<style>
.label { font-weight: bold; }
</style>
Copy the code

Although we can work around these issues by using custom element names (such as custom-Progressbar) to normalize the rules, and then initialize all the other attributes in the following way

all: initial
Copy the code

But Shadow DOM provides a more elegant solution by introducing an encapsulation layer at the external divs so that the internal implementation (such as the div created for labels and bars) is invisible to users of the progress bar component. Also, CSS styles defined for the progress bar do not interfere with the rest of the page and vice versa. To do this, we first create a ShadowRoot on the progress bar with a call:

attachShadow({mode: 'closed'})
Copy the code

Then attach the various DOM implementations needed for its implementation. Suppose we still use div to attach the Shadow Root as follows:

<body> <template id="progress-bar-template"> <div class="progress"> <div class="bar"></div> <div class="label">0%</div> </div> <style> .progress { position: relative; border: solid 1px; width: 100px; height: 1rem; } .progress > .bar { background: red; height: 100%; } .progress > .label { position: absolute; top: 0; width: 100%; text-align: center; The font - size: 0.8 rem; } </style> </template> <script> function createProgressBar() { var progressBar = document.createElement('div'); var shadowRoot = progressBar.attachShadow({mode: 'closed'}); shadowRoot.appendChild(document.getElementById('progress-bar-template').content.cloneNode(true)); progressBar.updateProgress = function (newPercentage) { shadowRoot.querySelector('.label').textContent = newPercentage + The '%'. shadowRoot.querySelector('.bar').style.width = newPercentage + '%'; } return progressBar; } var p = createProgressBar() document.body.appendChild(p) p.updateProgress(22) </script></body>Copy the code

Notice that the style element is inside the template element and is cloned into Shadow Root along with the div. This allows the scope of style rules defined in the shadow root. Style rules defined outside Shadow Root do not apply to elements inside Shadow Root.

Using open mode, you can access the Shadow DOM through the shadowRoot attribute of the HTML element. Off mode you can’t. ShadowRoot will return NULL. Closed mode is designed to prevent any access to nodes in the Shadow Root from the outside world.

Translation from:

Introducing Slot-Based Shadow DOM API | WebKit