Search code examples
cssweb-componentshadow-domnative-web-component

CSS: How to target ::slotted siblings in Shadow DOM root?


I know that the spec currently only allows compound selectors for ::slotted, i.e. ::slotted(my-first + my-second) is not allowed, but should something like this be working?

::slotted(x-first) + ::slotted(x-second) { /* css */ }

Is there any way to target slotted siblings (other than with global css)? And if not, where would I file such a request? Thanks.


Solution

  • Sure you can select siblings of slots / slotted.

    The thing you can not do is select a element which has been slotted and is not a top-level node.

    Select siblings:

    slot[name=<slotname>] ~ <selector>

    Select slotted top-level node

    ::slotted(<compound-selector>)

    A compound-selector contains a tag/class/id/name etc. but must not have any combinators. Like <space> for example.

    .myClass OK

    <anyTag>[<anyAttribute>[=<anyValue>]] OK

    .<myClass> > .<anotherClass> NO

    Examples

    var element = document.querySelector('.templateMe');
    var shadow = element.attachShadow({mode: 'open'});
    var template = document.querySelector('.myTemplate');
    shadow.appendChild(template.content.cloneNode(true));
    <template class="myTemplate">
      <style type="text/css">
        ::slotted([slot=slot1]) { /* slot1 every slotted element - YES */
          color: red;
        }
        
        slot[name=slot1] { /* slot1 itself - YES */
          text-decoration: underline;
        }
        
        slot[name=slot1] + .siblingA { /* slot1 siblingA (direct sibling) - YES */
          color: green;
        }
        
        slot[name=slot1]  ~ .siblingB { /* slot1 siblingB (any sibling) - YES */
          color: orange;
        }
        
        slot[name=slot2]::slotted(.selectMeA) { /* slot2 TOP-LEVEL CHILD (slotted) - YES */
          color: purple;
        }
        
        slot[name=slot2]::slotted(.selectMeB) { /* slot2 NOT TOP-LEVEL CHILD - NO */
          font-weight: bold;
        }
        
        slot[name=slot2]::slotted(.selectMeC[name=myName]) { /* slot2 TOP-LEVEL CHILD (slotted) - YES */
          color: khaki;
        }
        
        slot[name=slot2] + .siblingC { /* slot2 sibling - YES */
          color: blue;
        }
        
      </style>
      <div>
        <slot name="slot1"></slot>
        <div class="siblingA">Sibling A of Slot 1</div>
        <div class="siblingB">Sibling B of Slot 1</div>
      </div>
      <hr/>
      <div>
        <slot name="slot2"></slot>
        <div class="siblingC">Sibling C of Slot 2</div>
      </div>
    </template>
    
    <div class='templateMe'>
      <span slot="slot1">Im in Solt 1</span>
      <span slot="slot2" class="selectMeA">
        Im in Solt 2, im selectable.
        <div class='selectMeB'>
          NOT selectable (because no top level node of slotted)!
        </div>
      </span>
      <span slot="slot2" class="selectMeC" name="myName">Im in Solt 2 too and selectable!</span>
    </div>

    More here.

    slotted elements (coming from light DOM), ::slotted(selector) allows to select slotted elements themselves, but not their children.