PeakLab
Back to glossary

Shadow DOM

Browser API enabling encapsulation of DOM structure, styles, and behavior for web components, completely isolating their implementation.

Updated on January 27, 2026

Shadow DOM is a native web technology that creates an isolated DOM tree attached to an element, invisible from the main DOM. This encapsulation ensures that a component's styles and scripts don't leak to the rest of the page and vice versa. It forms one of the four pillars of Web Components alongside Custom Elements, HTML Templates, and ES Modules.

Shadow DOM Fundamentals

  • Creation of a parallel DOM tree (shadow tree) attached to a host element, invisible from document.querySelector
  • Bidirectional CSS encapsulation: external styles don't affect Shadow DOM and its styles don't affect the outside
  • Slots enabling projection of light DOM content into the shadow tree with complete control over placement
  • Open and closed modes defining programmatic accessibility of the shadow root via JavaScript

Shadow DOM Benefits

  • Complete style isolation preventing CSS conflicts and enabling simple naming conventions without complex methodologies (BEM, SMACSS)
  • JavaScript behavior encapsulation protecting component internal logic from external modifications
  • Guaranteed reusability: a component works identically regardless of its integration context
  • Optimized performance through reduced CSS scope and isolated DOM tree facilitating rendering engine work
  • Native web standard supported by all modern browsers without external dependencies

Practical Example

custom-button.ts
class CustomButton extends HTMLElement {
  constructor() {
    super();
    
    // Attach Shadow DOM in 'open' mode
    const shadow = this.attachShadow({ mode: 'open' });
    
    // Component structure
    shadow.innerHTML = `
      <style>
        /* Completely isolated styles */
        :host {
          display: inline-block;
        }
        
        button {
          background: var(--button-bg, #007bff);
          color: var(--button-color, white);
          border: none;
          padding: 0.75rem 1.5rem;
          border-radius: 0.25rem;
          cursor: pointer;
          font-size: 1rem;
        }
        
        button:hover {
          opacity: 0.9;
        }
        
        ::slotted(svg) {
          margin-right: 0.5rem;
          vertical-align: middle;
        }
      </style>
      
      <button part="button">
        <slot name="icon"></slot>
        <slot>Click here</slot>
      </button>
    `;
    
    // Encapsulated logic
    shadow.querySelector('button')?.addEventListener('click', () => {
      this.dispatchEvent(new CustomEvent('custom-click', {
        bubbles: true,
        composed: true
      }));
    });
  }
}

customElements.define('custom-button', CustomButton);

HTML usage with content projection via slots:

index.html
<style>
  /* These styles DON'T affect Shadow DOM */
  button {
    background: red; /* No effect on custom-button */
  }
  
  /* Customization via CSS Custom Properties */
  custom-button {
    --button-bg: #28a745;
    --button-color: white;
  }
  
  /* Targeting via ::part() */
  custom-button::part(button) {
    box-shadow: 0 2px 4px rgba(0,0,0,0.1);
  }
</style>

<custom-button>
  <svg slot="icon" width="16" height="16">...</svg>
  Save
</custom-button>

Shadow DOM Implementation

  1. Create a class extending HTMLElement to define the Custom Element container
  2. Attach a Shadow Root in the constructor with attachShadow({ mode: 'open' }) for accessibility or 'closed' for total isolation
  3. Define HTML structure and encapsulated CSS styles by injecting content into shadowRoot.innerHTML or via DOM API
  4. Use :host, :host(), :host-context() pseudo-classes to style the host element and ::slotted() for projected content
  5. Expose styleable parts via the part attribute and define CSS Custom Properties for controlled customization
  6. Implement private JavaScript logic by attaching events to Shadow DOM elements
  7. Register the component with customElements.define('element-name', ElementClass) following kebab-case convention

Encapsulation Strategy

Use 'open' mode to facilitate debugging and testing. The 'closed' mode offers illusory security as it can be bypassed. Prefer intentionally exposing customization points via part, CSS Custom Properties, and custom events rather than completely locking access.

Tools and Ecosystem

  • Lit: lightweight Google library for creating Web Components with Shadow DOM and declarative reactivity
  • Stencil: compiler generating optimized Web Components with TypeScript and JSX support
  • Open WC: toolset, recommendations, and starters for developing standards-based Web Components
  • Chrome DevTools: complete Shadow DOM inspection with tree visualization and CSS debugging
  • webcomponents.org: community catalog of reusable components using Shadow DOM
  • construct-style-sheets-polyfill: polyfill for Constructable Stylesheets enabling style sharing between Shadow Roots

Shadow DOM represents a paradigm shift in frontend architecture by bringing native encapsulation at the browser level. For teams developing design systems or large-scale reusable components, this technology eliminates CSS conflict issues and guarantees long-term maintainability. Its growing adoption in modern frameworks (Ionic, Salesforce Lightning) and enterprise component libraries demonstrates its value for building robust and predictable interfaces.

Themoneyisalreadyonthetable.

In 1 hour, discover exactly how much you're losing and how to recover it.

Web development, automation & AI agency

contact@peaklab.fr
Newsletter

Get our tech and business tips delivered straight to your inbox.

Follow us
Crédit d'Impôt Innovation - PeakLab agréé CII

© PeakLab 2026