The ::part
CSS pseudo-element represents any element within a shadow tree.
Let’s say we have below ProfileCard
class to define our custom element profile-card
.
export default class ProfileCard extends HTMLElement {
constructor() {
super()
this.attachShadow({ mode: 'open' })
}
connectedCallback() {
this.shadowRoot.innerHTML = `
<h2>Hi there</h2>
<p>
My name is ${this.getAttribute('name')}.
I'm a big fan of web components.
</p>
<style>
/* some styles here inside shadow root */
</style>
`
}
}
customElements.define('profile-card', ProfileCard);
<profile-card name="Brandon"></profile-card>
h2 {
/* this will have no effect on h2 inside our profile-card */
font-size: 2rem;
}
With current structure, other than setting CSS custom property and pass it down into this component, there is no way to style h2
heading with plain CSS outside of the profile-card
’s shadow root. And sometimes it’d be really nice to allow people consuming our components to be able to style the elements inside shadow root. This is where ::part
comes in handy.
We’ll need to add a part
attribute on h2
heading.
export default class ProfileCard extends HTMLElement {
// ...
connectedCallback() {
this.shadowRoot.innerHTML = `
<h2 part="heading">Hi there</h2>
<p>
My name is ${this.getAttribute('name')}.
I'm a big fan of web components.
</p>
<style>
/* some styles here inside shadow root */
</style>
`
}
}
Now we can use shiny ::part
pseudo-element to style our heading outside of shadow root.
/* inside () is where the part="green" attribute value */
::part(heading) {
font-size: 2rem;
}
This is good, but this style applies all custom elements that have a part
attribute. We can style the specific element’s part by adding a tag name in front like this.
profile-card::part(heading) {
font-size: 2rem;
}
Like class
attribute, part
attribute can also accept multiple values. Taking a step further, we’re adding one more value to it.
export default class ProfileCard extends HTMLElement {
// ...
connectedCallback() {
this.shadowRoot.innerHTML = `
<h2 part="heading uppercase">Hi there</h2>
<p>
My name is ${this.getAttribute('name')}.
I'm a big fan of web components.
</p>
<style>
/* some styles here inside shadow root */
</style>
`
}
}
Now we can change the heading to uppercase.
profile-card::part(uppercase) {
text-transform: uppercase;
}
We can also check to see if we have both green
and uppercase
value.
/*
unlike class name,
it needs a space between "green" and "uppercase",
otherwise it will have on effect
*/
profile-card::part(heading uppercase) {
color: lightseagreen;
}
One thing to keep in mind is that the ::part()
pseudo-element has no CSS specificity, so here color: orange
will override color: lightseagreen
.
profile-card::part(heading uppercase) {
color: lightseagreen;
}
profile-card::part(heading uppercase) {
color: orange;
}