CSS Light DOM vs Shadow DOM Styling Precedence

This article explains the styling precedence and specificity rules between the light DOM and the shadow DOM in modern web components. It details how style encapsulation works, how light DOM styles interact with the shadow boundary, and the exact hierarchy that determines which declaration wins when conflicts occur across host selectors, slotted content, inherited properties, and CSS custom properties.


Encapsulation and the Shadow Boundary

In standard web development, the light DOM refers to the regular document tree governed by the standard CSS cascade. The shadow DOM introduces an encapsulated subtree attached to an element (the shadow host).

By default, CSS written inside the light DOM cannot directly select elements inside a shadow tree, and styles defined within a shadow root cannot leak out into the document. However, interactions occur at the boundary points: the shadow host itself, slotted elements, and inherited properties.


Precedence at the Shadow Host (:host)

The shadow host is the element in the light DOM that contains the shadow tree. It can be styled from both contexts: from the outside using a standard selector (e.g., my-element) and from the inside using the :host pseudo-class.

  • Light DOM overrides Shadow DOM by default: Styles applied to the host from the outer light DOM take precedence over :host styles declared inside the shadow DOM, regardless of CSS specificity. For example, my-element { display: block; } in the light DOM will override :host { display: inline-block; } inside the shadow DOM.
  • The !important exception: If the shadow DOM defines a rule on :host using !important, it overrides normal and even !important declarations applied from the light DOM.

Inherited Properties

CSS properties that naturally inherit—such as color, font-family, and line-height—cross the shadow boundary automatically.

  • Inherited Light DOM styles are low precedence: Light DOM properties inherit down into the shadow tree only as baseline values.
  • Internal definitions always win: Any explicit property definition on an element inside the shadow DOM will override an inherited value from the light DOM, even if the light DOM rule had high specificity or was marked !important. Inheritance operates at a lower priority than explicit targeting.

Slotted Content (::slotted())

Slotted content consists of light DOM nodes placed into a <slot> element inside the shadow DOM. Because these nodes fundamentally reside in the light DOM, precedence favors the outside document:

  1. Light DOM styles win: Direct selectors in the light DOM targeting slotted elements override internal ::slotted() rules from the shadow DOM.
  2. ::slotted() limitations: The ::slotted() selector only targets top-level slotted nodes, not nested children, and carries lower precedence than any direct light DOM styling targeting the same node.

CSS Custom Properties

CSS custom properties (CSS variables) pierce the shadow boundary through inheritance. They provide the standard mechanism for light DOM contexts to theme shadow DOM components without breaking encapsulation.

  • If a custom property is declared on the host or an ancestor in the light DOM, the shadow DOM can consume it via var(--custom-property).
  • Precedence follows standard inheritance: an internal redefinition of the custom property inside the shadow DOM overrides the inherited value for that component and its descendants.

Summary of Precedence Order

When conflicts arise across the boundary, precedence ranks from highest to lowest:

  1. Shadow DOM :host rules with !important
  2. Light DOM host selectors with !important
  3. Light DOM direct rules on slotted content
  4. Light DOM host selectors (normal priority)
  5. Shadow DOM :host selectors (normal priority)
  6. Shadow DOM ::slotted() rules
  7. Shadow DOM internal rules (overriding light DOM inherited values)
  8. Light DOM inherited values