Skip to content

Style Encapsulation

The shadow root acts as a two-way style barrier:

  • Styles inside the shadow root apply only to the shadow tree. They cannot leak out and affect elements in the light DOM.
  • Styles in the light DOM (page CSS, external stylesheets) cannot pierce the shadow boundary and style elements inside the shadow tree.

This is the core value of Shadow DOM — you can build components that are truly self-contained, with no risk of accidental style collisions.

Consider a shadow element that declares .box { color: red; } inside its shadow root:

class EncDemo extends HTMLElement {
connectedCallback() {
this.attachShadow({ mode: 'open' });
this.shadowRoot.innerHTML =
'<style>.box { color: red; font-weight: bold; }</style>' +
'<div class="box">Red — shadow style</div>';
}
}

The .box { color: red; } rule has absolutely no effect on any .box element that exists outside this component.

Now consider page-level CSS that targets .box:

/* page stylesheet */
.box {
color: blue;
font-weight: bold;
border: 2px solid blue;
}

This rule applies to every .box in the light DOM. It does not apply to the .box inside the shadow root of <enc-demo>. The shadow boundary blocks it.

The demo below has two .box elements with the same class name. The one outside the custom element is styled blue by the page CSS. The one inside the shadow root is styled red by the shadow CSS. Neither style crosses the boundary.

Both div elements carry class="box", but they are styled independently because the shadow boundary separates them.

A page stylesheet declares `.title { color: red; }`. Does this rule apply to a `.title` element inside a shadow root?
A shadow root contains `<style>p { font-size: 2rem; }</style>`. Which elements does this rule affect?
Which of the following CAN cross the shadow boundary?
What is the primary benefit of style encapsulation in Shadow DOM?