CSS ::slotted() Pseudo-Element in Web Components

The ::slotted() CSS pseudo-element is used within a Web Component's Shadow DOM to select and style elements that are projected into a <slot>. This article covers the fundamental purpose of ::slotted(), how to write its syntax, how specificity works between the component and the light DOM, and the key limitations developers encounter when styling slotted content.

The Purpose of ::slotted()

When building Web Components using Shadow DOM, styles defined inside the shadow root are scoped exclusively to that component. However, components frequently include <slot> elements, which accept markup passed from the outside page (the "light DOM").

Because slotted elements technically remain in the light DOM, standard shadow DOM selectors cannot reach them. The ::slotted() pseudo-element bridges this boundary, allowing the component author to define default or contextual styles for incoming slotted elements from within the component's internal stylesheet.

Syntax and Basic Usage

The ::slotted() pseudo-element must take a selector argument specifying which elements within the slot to target.

/* Style any <p> element placed in a slot */
::slotted(p) {
  color: #333333;
  margin-bottom: 1rem;
}

/* Style only elements with a specific class inside a slot */
::slotted(.highlight) {
  background-color: yellow;
}

/* Target elements within a specific named slot */
slot[name="header"]::slotted(h1) {
  font-size: 1.5rem;
}

If you want to style all elements placed inside a slot, use the universal selector:

::slotted(*) {
  box-sizing: border-box;
}

Key Rules and Limitations

While ::slotted() provides access to external nodes, it operates under strict constraints designed to preserve DOM encapsulation.

1. Only Direct Children Can Be Targeted

The selector passed to ::slotted() only matches top-level nodes directly passed into the slot. It cannot target nested descendants of slotted elements.

  • Works: ::slotted(div) selects <div slot="content">
  • Fails: ::slotted(div span) or ::slotted(span) will not match a <span> located inside that <div>.

2. Simple Selectors Only

The argument inside ::slotted() must be a simple selector or compound selector representing the slotted node itself. You cannot use complex combinators (like descendant or child > selectors) inside the parentheses.

3. Light DOM Styles Take Precedence

CSS specificity works differently across the shadow boundary. Any styles applied to the slotted elements from the host document (the light DOM) will override the ::slotted() styles defined inside the Shadow DOM, regardless of the shadow selector's specificity. The Shadow DOM styles act primarily as fallback or default styling for the projected content. To override light DOM styles from inside the component, !important must be added to the property rule.