Custom element сам по себе не защищает стили: правило страницы p { color: red } попадёт и внутрь компонента. Shadow DOM даёт компоненту собственный изолированный DOM и CSS, а <template> и <slot> упрощают шаблоны и передачу контента.

Граница стилей Shadow DOM
Граница стилей Shadow DOM

Shadow DOM: host, shadow root, light DOM

  • host — элемент, несущий shadow root;
  • shadow root — изолированное поддерево;
  • light DOM — дети, которых вы пишете внутри host.
js
class FancyCard extends HTMLElement {
  constructor() {
    super();
    const root = this.attachShadow({ mode: 'open' });
    root.innerHTML = `
      <style>p { color: crimson; }</style>
      <p>Inside the shadow</p>`;
  }
}
customElements.define('fancy-card', FancyCard);

const card = document.createElement('fancy-card');
document.body.append(card);

console.log(card.shadowRoot.mode);                            // open
console.log(card.shadowRoot.querySelector('p').textContent);  // Inside the shadow
console.log(document.querySelector('p'));                     // null

⚠️ mode: 'closed' не даёт настоящей безопасности (и усложняет, например, тесты и расширения браузера). Большинство компонентов выбирают open.

Что проходит сквозь границу