Max Design

Published:

What is the Shadow DOM?

The Shadow DOM is a way for web components to keep some of their internal structure private.

Think of it as a small, self-contained “mini-DOM” living inside an element.

Why does this exist?

Because it gives the component its own private space for markup, styles, and behaviour — separate from the rest of the page.

This means you don’t need to worry about:

In short: this encapsulation means you can drop a web component into a page and trust that it won’t break anything, and nothing on the page will break it.

Inside <fancy-button>, the shadow tree might contain:

All of this is hidden inside the component’s shadow tree.

Well, technically it is hidden from the DOM tree, but not hidden from the browser’s internal representation.

What the Shadow DOM looks like in the DOM

Even though the Shadow DOM is part of the page, it doesn’t appear as normal DOM children.

In DevTools, you have to expand the shadow root to see what’s inside. Until you do, the component looks like it contains nothing at all.

Before you expand the shadow root, you only see:

<fancy-button></fancy-button>

But after it is expanded, it might look like this:

<fancy-button>
  #shadow-root
    <button>
      <span>Buy now</span>
    </button>
</fancy-button>

Flattening the Shadow DOM

Screen readers do not see the shadow root itself.

Without flattening, the <button> would be inaccessible because it lives behind a shadow boundary.

Browsers solve this by flattening the shadow tree when building the accessibility tree.

Flattening removes the accessibility boundary of the shadow root and exposes the internal nodes as if they were normal children in the accessibility tree (not the DOM tree).

During flattening, the browser resolves slotting (which light DOM nodes appear in which <slot>), and exposes the final composed structure to assistive technologies.

So, the accessibility tree could look something like:

Root
└─ fancy-button (generic container / group)
   └─ button  Name: "Buy now"

Note two things:

  1. The shadow root is not represented at all in the accessibility tree.
  2. The non-native fancy-button element is exposed with a generic role, because it has no inherent semantic meaning.

How different browsers do it

All major browsers flatten the shadow tree, but they do it at slightly different stages of their accessibility architecture.

Chrome (Blink)

Flattening happens inside the Blink accessibility tree in the renderer process. By the time the BrowserAccessibility tree is created, the shadow DOM is already flattened.

Firefox (Gecko)

Flattening happens in Gecko’s accessibility module. The accessibility tree reflects the composed tree (light DOM + shadow DOM combined), not the raw DOM.

Safari (WebKit)

WebKit exposes a flattened structure based on the composed tree, hiding shadow roots and slot wiring from assistive technologies.

Is screen reader performance affected by the Shadow DOM?

In general, no. The Shadow DOM does not introduce inherent performance problems for assistive technologies. Screen readers never interact with shadow roots directly. They only receive the final, flattened accessibility tree that combines everything into one structure.

If a page feels slow or laggy with a screen reader, it’s rarely because of the Shadow DOM. It usually comes from broader factors such as:

Component-heavy sites can sometimes feel slower, but not because they use web components or shadow roots. They simply tend to contain more elements and trigger more back-and-forth communication between the browser and the assistive technology.

Final takeaway

Screen readers only ever see a single, flattened accessibility tree that merges the light DOM and the shadow DOM into one seamless hierarchy. Shadow roots, slot wiring, and internal component structure are all handled by the browser long before assistive technologies are involved.