1

Here's my attempt, but the span elements do not have a deeppink border like I am hoping for (I'm in Google Chrome 83):

const d = document.querySelector('div')

const r = d.attachShadow({mode: 'open'})

r.innerHTML = `
  <style>
    /* This doesn't work as I was hoping: */
    ::slotted(p) span {
      border: 1px solid deeppink;
    }
    
    /* This doesn't work (and I wouldn't expect it to), but I tried it anyways: */
    ::slotted(span) {
      border: 1px solid deeppink;
    }
    
    /* This doesn't work either: */
    :host span {
      border: 1px solid deeppink;
    }
    
    /* This works, but not what I'm trying to do. */
    ::slotted(p) {
      background: #f9f9f9
    }
  </style>
  <slot></slot>
`
<div>
  <p><span>test</span></p>
  <p><span>test</span></p>
  <p><span>test</span></p>
  <p><span>test</span></p>
  <p><span>test</span></p>
</div>

How do we style descendants of distributed (slotted) children?

trusktr
  • 44,284
  • 53
  • 191
  • 263

1 Answers1

0
  • slotted content remains in lightDOM, is reflected to a <slot>
  • ::slotted(*) can only target the lightDOM SKIN with simple selectors

For long answer see: ::slotted CSS selector for nested children in shadowDOM slot

Update: example <div SLOT=Hello> content is not IN shadowDOM

<my-element>
  <div slot=Hello>Hello reflected (slotted) lightDOM DIV</div>
</my-element>

<my-element>
  <div slot=NoSlot>Hello not slotted lightDOM DIV</div>
</my-element>

<script>
  customElements.define('my-element', class extends HTMLElement {
    constructor() {
      super()
        .attachShadow({mode: 'open'})
        .innerHTML=`<slot name=Hello><b>I am shadowDOM SLOT content</b></slot>`;
    }
    connectedCallback() {
      console.log(this.shadowRoot.querySelector('slot').innerHTML)
    }
  });
</script>
Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343
Danny '365CSI' Engelman
  • 16,526
  • 2
  • 32
  • 49
  • Although this is technically the answer (I found the GitHub threads too), I hope the limitation can be uplifted. Using combinators with `::slotted` is an intuitive idea. – trusktr Jul 14 '20 at 04:52
  • (replying for other readers than Truskr) Yes, *intuitive* if you continue to think slotted content is part of shadowDOM. But **slotted content is not part of shadowDOM**, it is in lightDOM. The content you see in shadowDOM slots is a *reflection*. Any changes made in lightDOM are immediately reflected to the slot. – Danny '365CSI' Engelman Jul 14 '20 at 07:52
  • added code: And content inside a ``slot`` is not displayed if the slot is taken by lightDOM content.... but the innerHTML is still the ``slot`` content (in shadowDOM) – Danny '365CSI' Engelman Jul 14 '20 at 09:14
  • I was thinking intuitive relative to the actual DOM tree. Slotted content DOM tree is in the light tree. The "composed" tree is a virtual IDEA that doesn't exist in the normal DOM (f.e. it isn't represented with `childNodes`). So when I thought about `::slotted(foo) bar`, I was intuitively already thinking that it was selecting based on the light tree. It doesn't make intuitive sense otherwise, because even after slotting, there is no tree besides that. The descendants of the slotted element are "mirrored" or "rendered" at the new location, sure, but I'm thinking about _selecting_ them. – trusktr Jul 18 '20 at 17:04
  • So I think that the selector matching elements in the light dom in intuitive. Just like `:host` selects an element in the DOM, so would `::slotted`, and that element selected would be right in the place where you found it (in the light DOM, the only DOM that users manipulate). – trusktr Jul 18 '20 at 17:07
  • Yes, and that's what ``::content`` did in V0. Which was scrapped from V1 and replaced with ``::slotted``, with approval from everyone involved, because they experienced performance issues. So, yes, it is intuitive, just didn't work properly... – Danny '365CSI' Engelman Jul 18 '20 at 18:52