Follow This Blog For more... 😊

About Shadow DOM & shadowRoot

Shadow DOM & shadowRoot in JavaScript – The Complete Beginner-to-Advanced Guide

If you’ve ever built complex UIs, you’ve probably faced these problems:

  • Styles bleeding into other components
  • CSS conflicts across pages
  • Script interference
  • Hard-to-maintain UI modules

What if you could create your own private DOM—a protected area where:

  • Your CSS NEVER leaks outside
  • Outside CSS NEVER affects it
  • Your DOM structure is hidden
  • Everything inside remains completely self-contained

Welcome to the Shadow DOM.

At the center of it all is the shadowRoot.


🔶 1. What Exactly Is the Shadow DOM?

The Shadow DOM is a hidden, encapsulated DOM tree attached to an element, separated from the main document DOM.

It is used mainly in Web Components to create custom, reusable HTML elements with private DOM and styles.

Think of it as:

A mini-webpage inside an element — with its own HTML, CSS, and JS — isolated from the outside world.


🔶 2. What Is shadowRoot?

The shadowRoot is the root node of the shadow DOM.

It represents the entry point into this private DOM.

You create a shadowRoot using:

element.attachShadow({ mode: "open" });

And this shadowRoot becomes the container for your private DOM nodes.


🔶 3. Why Do We Need shadowRoot?

Because it gives you:

✔ Encapsulation

No CSS conflicts. No script interference.

✔ Style Isolation

Your component looks the same everywhere.

✔ DOM Privacy

Outside JS cannot access inner DOM (if mode: 'closed').

✔ Reusability

Build design systems, UI libraries, components.


🔶 4. Creating a shadowRoot (Step-by-Step)

Example:

<div id="box"></div>

<script>
  const box = document.querySelector("#box");

  const shadow = box.attachShadow({ mode: "open" });

  shadow.innerHTML = `
    <style>
      p { color: red; font-size: 20px; }
    </style>
    <p>Hello from Shadow DOM!</p>
  `;
</script>

Result:

  • <p> inside the shadow DOM appears red
  • If the main document has styles like p { color: blue; }, it will NOT affect this paragraph.

🔶 5. mode: "open" vs mode: "closed"

| Mode | Meaning | Can access via element.shadowRoot? | | ---------- | ---------------------------------- | ---------------------------------- | | open | Shadow root is accessible publicly | ✔ Yes | | closed | Shadow root is hidden from outside | ❌ No |

Example of closed shadow DOM:

element.attachShadow({ mode: "closed" });

Trying to access:

console.log(element.shadowRoot); // null

Used for high-security components where internal structure must be hidden.


🔶 6. Adding Elements Inside shadowRoot

Append elements like normal DOM

const shadow = element.attachShadow({ mode: "open" });

let btn = document.createElement("button");
btn.textContent = "Click Me";

shadow.append(btn);

🔶 7. Styling Inside the Shadow DOM

Shadow DOM protects styles in both directions.

Example:

shadow.innerHTML = `
  <style>
    button {
      background: black;
      color: white;
    }
  </style>
  <button>Shadow Button</button>
`;

Outside CSS like:

button {
  background: yellow;
}

Will NOT change the shadow DOM button.


🔶 8. Host Selector – Styling the Host Element

Sometimes you want to style the custom element itself, not its internal nodes.

Use:

:host {
  display: block;
  padding: 10px;
  border: 2px solid black;
}

🔶 9. :host-context() – Styling Based on Outer DOM

Example:

:host-context(.dark-theme) {
  background: black;
  color: white;
}

The shadow element reacts to parent page conditions without exposing itself.


🔶 10. Slotting Content into Shadow DOM

Shadow DOM gives a private DOM, but you may want to allow user content.

Use <slot>:

shadow.innerHTML = `
  <style>
    ::slotted(span) {
      color: green;
    }
  </style>

  <div>
    <slot></slot>
  </div>
`;

HTML outside:

<my-card>
  <span>User Content</span>
</my-card>

Slot displays user content inside the shadow DOM without breaking encapsulation.


🔶 11. Full Example – Creating a Custom Component Using shadowRoot

Step 1: Define custom element

class MyBox extends HTMLElement {
  constructor() {
    super();

    const shadow = this.attachShadow({ mode: "open" });

    shadow.innerHTML = `
      <style>
        div {
          padding: 20px;
          background: lightblue;
          font-size: 18px;
        }
      </style>

      <div>
        <slot></slot>
      </div>
    `;
  }
}

customElements.define("my-box", MyBox);

Step 2: Use it in HTML

<my-box>Hello, I am inside a shadow DOM!</my-box>

🔶 12. Accessing shadowRoot (open shadow DOM)

const el = document.querySelector("my-box");
console.log(el.shadowRoot); // ShadowRoot object

🔶 13. Why You Should Not Overuse Closed Shadow DOM

  • Hard to debug
  • Not accessible to developers
  • Conflicts with dev tools
  • Not recommended unless necessary

Most modern component libraries use open mode.


🔶 14. Shadow DOM Event Behavior

Inside the shadow DOM, events still bubble up but with protection.

If a button inside the shadow DOM is clicked:

  • The event bubbles outward
  • But the DOM path is rewritten to hide private nodes
  • Outside code cannot see the internal DOM structure

Example:

button.addEventListener("click", (e) => console.log(e.composedPath()));

Shadow-internal nodes may appear only when composed: true is allowed.


🔶 15. Shadow DOM vs Regular DOM

| Feature | Regular DOM | Shadow DOM | | ---------------- | ----------- | --------------- | | Style isolation | ❌ No | ✔ Yes | | Script isolation | ❌ No | ✔ Partial | | Encapsulation | ❌ None | ✔ Strong | | Reusability | Average | Excellent | | Used in | All HTML | Custom elements |


🔶 16. Real World Uses of Shadow DOM

You rely on shadow DOM every day in modern web dev:

  • <video> element UI
  • <input> styling
  • Browsers' custom widgets
  • Web components (frameworks like Lit, Stencil, Shoelace)
  • Design systems
  • Component libraries

Shadow DOM powers most of the modern “component-style architecture”.


⭐ Final Summary

shadowRoot is the root of a shadow DOM: A private, isolated DOM attached to an element.

With a shadow root, you get:

✔ Encapsulation ✔ Private CSS ✔ Private DOM ✔ DOM separation ✔ No CSS bleeding ✔ No conflicts ✔ Support for slots ✔ Custom components

Shadow DOM is the foundation of modern Web Components, making them maintainable, scalable, and conflict-free.


If you'd like next:

  • Topic: closed vs open shadow DOM
  • Topic: lifecycle callbacks in Web Components
  • Topic: slots vs templates
  • Topic: styling strategies for web components

Tell me the next topic!

Comments

Popular Posts