CSS :has-slotted Pseudo-Class

The CSS :has-slotted pseudo-class selects a <slot> element when content has been assigned to it. It allows web components to style slots differently depending on whether they contain assigned content or display their fallback content.

:has-slotted Syntax

slot:has-slotted {
  property: value;
}

The :has-slotted pseudo-class does not accept arguments. It matches a <slot> element when at least one node is assigned to that slot.

Example Syntax

slot:has-slotted {
  display: block;
  padding: 12px;
  border: 2px solid #0088cc;
}

This rule styles a slot when assigned content is present.

Named Slot

slot[name="header"]:has-slotted {
  border-bottom: 2px solid #0088cc;
}

This selector matches a named header slot when content has been assigned to it.

Specificity

The :has-slotted pseudo-class has a specificity of 0-1-0. Combined with the slot element selector, its specificity becomes 0-1-1.

How :has-slotted Works

The :has-slotted pseudo-class checks whether a slot has assigned nodes. These nodes come from the light DOM of the element hosting the shadow tree.

When at least one node is assigned, the slot matches :has-slotted. When no nodes are assigned, the slot does not match.

Assigned Content

<template id="card-template">
  <slot name="title">Default Title</slot>
</template>

<my-card>
  <h2 slot="title">CSS Tutorial</h2>
</my-card>

The heading is assigned to the named title slot when the template is used in a shadow root attached to the custom element.

Matching the Slot

slot[name="title"]:has-slotted {
  color: #003366;
}

This selector targets the slot element, not the assigned heading itself.

Shadow Tree Styles

Styles for slots are normally defined inside the component's shadow root. A stylesheet in the main document does not ordinarily select slot elements inside a shadow tree.

Shadow DOM and Slots

Shadow DOM allows a web component to maintain its own internal document structure and styles.

The <slot> element provides an insertion point where content supplied by the component's user can appear.

Named Slots

<template id="profile-template">
  <div class="profile">
    <slot name="heading">Profile</slot>
    <slot name="description">No description available.</slot>
  </div>
</template>

The template contains two named slots. Each can receive matching light DOM content from the custom element.

Assigning Content

<my-profile>
  <h2 slot="heading">CSS Developer</h2>
  <p slot="description">Learning CSS selectors.</p>
</my-profile>

The slot attributes identify the insertion points for the heading and paragraph.

Default Slots

<template id="message-template">
  <slot>No message provided.</slot>
</template>

A slot without a name attribute is a default slot. It receives eligible content that is not assigned to a named slot.

:has-slotted Matching Behavior

The pseudo-class matches based on assigned nodes, not whether the assigned content contains visible text.

Matching Conditions

Condition Matches :has-slotted?
A heading is assigned to the slot Yes
A paragraph is assigned to the slot Yes
A text node is assigned to the slot Yes
Only whitespace text is assigned Yes
No nodes are assigned No
Only fallback content exists inside the slot No
An assigned element contains no text Yes

Whitespace Matters

A slot can match :has-slotted when its only assigned content is a whitespace text node. The selector does not check whether the content is visually meaningful.

Empty Elements

An assigned empty element still counts as an assigned node. For example, an empty <span> assigned to a slot causes it to match.

Fallback Content

A slot can contain fallback content that is displayed when no nodes are assigned to it.

Fallback Example

<slot name="message">No message available.</slot>

If no content is assigned to the message slot, the fallback text is displayed.

Styling Assigned and Fallback States

slot[name="message"] {
  display: block;
  padding: 10px;
  background-color: #f2f2f2;
}
slot[name="message"]:has-slotted {
  background-color: #eaf6fc;
  border-left: 3px solid #0088cc;
}

The base styles apply to the slot whether or not it has assigned content. The :has-slotted styles apply only when assigned content is present.

Styling Empty Slots

slot:not(:has-slotted) {
  color: #777;
  font-style: italic;
}

This selector targets slots without assigned nodes, allowing their fallback content to have a different appearance.

:has-slotted vs. ::slotted()

Both selectors are associated with Shadow DOM slots, but they select different elements.

Comparison

Selector Purpose
:has-slotted Selects a slot element when it has assigned nodes.
::slotted() Selects assigned elements matching a specified selector.

Styling the Slot

slot:has-slotted {
  border: 2px solid #0088cc;
}

The border is applied to the slot element.

Styling Assigned Elements

::slotted(p) {
  color: #003366;
  font-weight: bold;
}

This rule styles paragraph elements assigned to slots in the shadow tree.

Important Difference

The ::slotted() pseudo-element does not select arbitrary descendants inside an assigned element. It matches the assigned element itself.

Dynamic Slot Content

Assigned slot content can change when elements are added, removed, or reassigned.

Adding Assigned Content

const component = document.querySelector("my-card");
const heading = document.createElement("h2");

heading.slot = "title";
heading.textContent = "New Title";
component.appendChild(heading);

The new heading is assigned to the matching slot when the component has a shadow root containing that named slot.

Removing Assigned Content

component.querySelector('[slot="title"]')?.remove();

If this removes the last assigned node, the slot no longer matches :has-slotted.

The slotchange Event

const slot = component.shadowRoot.querySelector('slot[name="title"]');

slot.addEventListener("slotchange", () => {
  console.log("Assigned content changed");
});

The slotchange event allows JavaScript to respond when a slot's assigned nodes change. This example assumes the component uses an open shadow root.

Limitations

The :has-slotted pseudo-class is specialized for Shadow DOM slot elements and has limited browser availability.

Limited Browser Support

Not all browsers implement :has-slotted. Unsupported browsers ignore CSS rules that depend on the pseudo-class.

Only Slot Elements

The selector is designed for <slot> elements. It does not provide general-purpose detection of child content in ordinary HTML containers.

Does Not Inspect Text Meaning

The selector detects assigned nodes, including whitespace. It does not determine whether the assigned content is meaningful or visible.

JavaScript Fallback

For broader compatibility, JavaScript can inspect assigned nodes using assignedNodes() and apply a class to the slot.

const slot = document.querySelector("my-card").shadowRoot.querySelector("slot");

function updateSlot() {
  slot.classList.toggle("has-content", slot.assignedNodes().length > 0);
}

slot.addEventListener("slotchange", updateSlot);
updateSlot();

This example assumes the custom element has an open shadow root. The .has-content class can be styled using ordinary CSS.

Best Practices

  • Use :has-slotted only for Shadow DOM slot elements.
  • Define slot styles within the component's shadow root.
  • Provide useful fallback content when a slot may be empty.
  • Remember that whitespace text nodes count as assigned content.
  • Use ::slotted() when the assigned elements themselves need styling.
  • Check browser support before relying on :has-slotted.
  • Use slotchange and assignedNodes() when a JavaScript fallback is required.
  • Test components with and without assigned content.

:has-slotted Example

This example creates a web component with a named slot. Select Add Content or Remove Content to change the assigned nodes.

The component includes a JavaScript fallback so the visual demonstration works in browsers that do not support :has-slotted.

HTML

<my-slot-demo></my-slot-demo>
<button type="button" id="add-content">Add Content</button>
<button type="button" id="remove-content">Remove Content</button>

CSS

slot {
  display: block;
  padding: 15px;
  border: 2px solid #ccc;
  background-color: #f2f2f2;
}
slot:has-slotted,
slot.has-content {
  border-color: #0088cc;
  background-color: #eaf6fc;
}

JavaScript

class MySlotDemo extends HTMLElement {
  constructor() {
    super();
    const shadow = this.attachShadow({ mode: "open" });
    shadow.innerHTML = `
      <style>
        slot {
          display: block;
          padding: 15px;
          border: 2px solid #ccc;
          background-color: #f2f2f2;
        }
        slot:has-slotted,
        slot.has-content {
          border-color: #0088cc;
          background-color: #eaf6fc;
        }
      </style>
      <slot name="message">No content assigned.</slot>
    `;
    const slot = shadow.querySelector("slot");
    const updateSlot = () => {
      slot.classList.toggle("has-content", slot.assignedNodes().length > 0);
    };
    slot.addEventListener("slotchange", updateSlot);
    updateSlot();
  }
}

customElements.define("my-slot-demo", MySlotDemo);

const component = document.querySelector("my-slot-demo");

document.getElementById("add-content").addEventListener("click", () => {
  if (component.querySelector('[slot="message"]')) return;
  const paragraph = document.createElement("p");
  paragraph.slot = "message";
  paragraph.textContent = "Assigned slot content is now present.";
  component.appendChild(paragraph);
});

document.getElementById("remove-content").addEventListener("click", () => {
  component.querySelector('[slot="message"]')?.remove();
});

Browser Result

Play in Editor

Note: The JavaScript fallback applies the .has-content class when nodes are assigned. The example therefore demonstrates the intended appearance even when native :has-slotted matching is unavailable.

Browser Support

Baseline: Limited availability. The :has-slotted pseudo-class is not supported consistently across major browsers. Use a fallback when the assigned-content state must be styled reliably.

For current compatibility information, visit Can I Use? and search for :has-slotted.

Specifications

The :has-slotted pseudo-class is defined in CSS Scoping Level 1. The specification describes matching a slot element based on whether it has assigned nodes.

CSS Scoping Level 1 - :has-slotted