Accessibility Now
Join our upcoming webinar about building accessible web applications! June 7, 2022.

CSS Encapsulation with Shadow DOM

Nii Yeboah
On Apr 28, 2017 1:39:00 PM

The Global Problem

The global scope of CSS can be problematic for many reasons. Every CSS rule we define has the potential to have wide-ranging and often unintended side effects. In other cases, a rule may have no effect due to conflicts with global styles. As applications increase in scale and complexity, maintainability and extensibility become increasingly challenging as a result of the global nature of CSS. There are a lot of different approaches to solving the CSS scoping problem:

Shadow DOM

In this tutorial, we focus on the browsers very own solution to CSS encapsulation which is the Shadow DOM. The Shadow DOM allows the browser to render DOM elements without putting them in the main DOM tree, which enables local scoping for HTML and CSS.

When creating custom elements with libraries like LitElement or Polymer, the creation of the Shadow DOM has been abstracted and is done automatically unless you explicitly change this behavior.

We will be looking at how to create a Shadow DOM using vanilla JavaScript. To do this, we call the attachShadow method on certain HTML elements or any custom element we define. The following HTML renders the text "Light DOM" in red because of the CSS rule that targets all <span> elements:

span {
color: red;
<div class="shadow-dom">
<span>Light DOM</span>
The words Light DOM in the color red.

We can create a Shadow DOM with a local <span> element and a local style targeting it like this:

const element = document.querySelector('.shadow-dom');
element.attachShadow({ mode: 'open' }); // (1)
element.shadowRoot.innerHTML = `
span {
color: green; // (2)
<span>Shadow DOM</span> // (3)
<slot></slot> // (4)
  1. Attach a Shadow DOM tree to the <div> element.

  2. Define a local CSS rule for <span> elements. This rule will not affect any <span> elements outside of the Shadow DOM.

  3. Place a <span> element in the Shadow DOM. This <span> element will not be affected by global CSS rules.

  4. Place a <slot> element in the Shadow DOM. This tells the browser where to render elements placed in the light DOM.

You must provide the ShadowRootInit parameter for the attachShadow method. This is an object with a mode property. The mode should always be "open" as this allows us to access the shadow DOM by referencing the elements shadowRoot property.
The words Shadow DOM written in green followed by the words Light DOM in the color red.

Live code example here.