Day 45: the specificity of ::slotted() content
posted on
It’s time to get me up to speed with modern CSS. There’s so much new in CSS that I know too little about. To change that I’ve started #100DaysOfMoreOrLessModernCSS. Why more or less modern CSS? Because some topics will be about cutting-edge features, while other stuff has been around for quite a while already, but I just have little to no experience with it.
When you pass an element to a web component through a <slot>
, you can select that element using the ::slotted()
pseudo-element and apply additional styles.
Let's take the following component. There's a paragraph in the shadow DOM and another paragraph coming from the light DOM, passed through a <slot>
, and there's a global style turning the background color of paragraphs aqua.
p {
background-color: aqua;
}
class SlotComponent extends HTMLElement {
constructor() {
super();
this.attachShadow({mode: 'open'});
const content = document.createElement('div')
content.innerHTML = `
<p>not slotted</p>
<slot></slot>
`
this.shadowRoot.appendChild(content)
}
}
customElements.define('slot-component', SlotComponent);
<slot-component>
<p>slotted</p>
</slot-component>
slotted
The global styles only apply to the slotted paragraph. We've already learned why in “Day 10: global styles and web components”.
If you add styles to the shadow DOM, you can see how these styles only apply to the paragraph inside the shadow DOM, but not to the slotted paragraph.
const styles = document.createElement('style')
styles.innerHTML = `
p {
background-color: salmon;
}
`
this.shadowRoot.appendChild(styles)
slotted
If you want to style slotted content from within the component, you can use the ::slotted()
pseudo-element.
const styles = document.createElement('style')
styles.innerHTML = `
p {
background-color: salmon;
}
::slotted(p) {
background-color: red;
}
`
this.shadowRoot.appendChild(styles)
slotted
As you can see, the background color didn't change. That's because by slotting content you're not moving it from the light DOM to the shadow DOM. The nodes physically stay where they are, they're just reflected inside the web component. This also means that global document styles still apply. By using ::slotted()
we can add additional styles, but by default these styles have lower specificity than global document styles.
That changes if we add !important
to the mix.
const styles = document.createElement('style')
styles.innerHTML = `
p {
background-color: salmon;
}
::slotted(p) {
background-color: red !important;
}
`
this.shadowRoot.appendChild(styles)
slotted
Further reading
- Day 10: global styles and web components
- Day 18: inheritable styles and web components
- Day 28: custom properties and web components
- Day 60: the ::part() pseudo-element
Overview: 100 Days Of More Or Less Modern CSS