cssstenciljsstencil-component

How to access elements inner two shadow dom


I'm using the follow web-component tree:

<x-typography>
  :shadow-root
    <x-select>
      :shadow-root
        <div class="select-container>
        </div>
    </x-select>
</x-typography>

And I need to override the background-color on select-container. I don't have access to <x-select> code, only <x-typography>.

I know how to :host and ::slotted works, I tried:

:host(x-typography):host(x-select) .select-container
:host(x-typography):host(x-select) .select-container
:host(x-typography :host(x-select)) .select-container

But none of them work.


Solution

  • You can use the ::part pseudo-element and exportparts attribute for this. It allows you to make custom styles for inner Shadow DOM element.

    You can specify a "styleable" part on any element in your shadow tree:

    <x-select>
      :shadow-root
        <header class="select-header"></header>
        <div class="select-container" part="container"></div>
    </x-select>
    

    And then you can specify custom styles for that part like:

    x-select::part(container){
      font-weight: bold;
    }
    

    Also it works with other pseudo selectors like :hover, :active...

    x-select::part(container):hover {
      opacity: 0.8;
    }
    

    But it doesn't work with nested parts. So, you cannot use it like:

    x-select::part(container)::part(aside) {
    }
    

    For that purpose you need to export the part via exportpart attribute.

    <x-bar>
      :shadow-root
      <x-foo exportparts="some-box: foo-some-box"></x-foo>
    </x-bar>
    

    However, if you need to support IE11 then it might be not the best option. From the other hand, it's supported by all modern browsers: https://caniuse.com/#search=%3A%3Apart

    So, your example would look like:

    // x-select
    
    
    render () {
      return (
        <Host>
          <div class="select-container" part="container"></div>
        </Host>
      )
    }
    
    // x-typography
    
    
    render () {
      return (
        <Host>
          <x-select exportparts="container: container"></x-select>
        </Host>
      )
    }
      
    
    <!-- usage -->
    
    <x-typography></x-typography>
    
    <style>
      x-typography::part(container) {
        color: blue;
      }
    </style>
    
    

    Here you can find a great explanation how part works: https://github.com/fergald/docs/blob/master/explainers/css-shadow-parts-1.md