Style Children of Shadow Dom: :Part Element

How do I select the :first-child of a shadow-dom ::part() of a web component

Unfortunately the spec (https://drafts.csswg.org/css-shadow-parts-1/#part) states that using 'structural pseudo-classes', such as :first-child is not supported with part:

The ::part() pseudo-element can take additional pseudo-classes after it, such as x-button::part(label):hover, but never matches the structural pseudo-classes or any other pseudo-classes that match based on tree information rather than local element information.

Can the CSS :part pseudo-selector be used to style nested web components?

Nope. It is not possible. It kind a breaks the encapsulation principle. The right way is to use proper theming. That means using a combination of:

::part - For direct theming of the component
:host-context - for theming based on the context
::slotted - For styling the slotted element inside the styling

For more dynamic theming, you can use above styles in combination with Element.matches API. Whatever the class/context that the user of the component has set, you can then change the styling of nested children component.

On a side note, modifying the styling of a decadent component (children of children) is a bad practice even when not using Shadow DOM or Web Components. It will result in a brittle non-maintainable CSS.

Edit Note:

:host-context is not implemented in all browsers and probably never will.

Use CSS selectors like :first-child inside shadow dom

I found a workaround for this in JS way.

For each slot, we have a eventHandler called (slotchange). By using that we can get the DOM event for the slot whenever the slot changes. Like this (HTML)

<custom-element (slotchange)="onSlotChanged($event)"></custom-element>

JS

onSlotChanged($event) {
console.log($event) // Go and research yourself about this event, you'll find many things usefull.
$event.target.assignedNodes() // This will give you the array of every elements, that are in side of the shadow dom
// Example usage, adding the margin-bottom to only first time (css :firsh-child)
$event.target.assignedNodes()[0].shadowRoot.getElementById('some-id').style.marginBottom = '10px'
}

If you only need to add a property to the element, you don't have to query shadowDom like "node.shadowRoot". But, if you want to access the element inside the shadowRoot of that element, you have to use that



Related Topics



Leave a reply



Submit