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-slottedonly 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
slotchangeandassignedNodes()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
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.
