How do I select all slotted by name?
Asked Answered
O

2

9

I am dealing with this situation...

<template>
  <slot name="thing"></slot>
  <slot name="other"></slot>
</template>

and an implementation like

<custom-element>
  <div slot="thing"> Thing 1 </div>
  <div slot="thing"> Thing 2 </div>
  <div slot="other"> Thing 3 </div>
</custom-element>

How do I use a CSS query to affect both Thing 1 & Thing 2 but excludes Thing 3?

Oddment answered 15/1, 2020 at 3:25 Comment(5)
[slot="thing"]{ border: 2px dashed #f00; } Attribute selectorsKnowhow
So would thing be like :head[slot="thing"] given shadow dom?Oddment
I'm not sure about the web-component implementation... I thought you were just looking for the css-selector... slot[name="thing"] maybe?Knowhow
The things I've found useful to try for web-components: in outside CSS :defined, [slot=...], and for the CSS inside the component, :host, ::slotted(), slot[name=...].Hitormiss
Sorry meant hostOddment
B
8

In the Shadow DOM <style> tag, you can apply CSS styles directly to the <slot> element as @admcfajn suggeded in its second comment:

slot[name="thing"] { .. }

But if you want to target an element from the light DOM when it's inserted in the Shadow DOM through a <slot> element, you should use the ::slotted() pseudo-element function.

::slotted( div[slot="thing"] ) { color: green }

will color in red the text inside the <div> with the attribute slot="name".

Important: the second solution is preferred, because the CSS from the light DOM has priority. Thereforce style inherited from the light DOM will override style from the slot element. See the example with background-color below:

customElements.define( 'custom-element', class extends HTMLElement {
  constructor() {
    super()
    this.attachShadow( { mode: 'open' } ).innerHTML = tpl.innerHTML
  }
} )
body { background-color: lightblue }
<template id=tpl>
  <style>
    ::slotted( [slot=thing] ) { background-color: green }
    slot[name="other"] { background-color: red }
  </style>
  <slot name="thing"></slot>
  <slot name="other"></slot>
</template>

<custom-element>
  <div slot="thing"> <div>Thing 1 </div></div>
  <div slot="thing"> Thing 2 </div>
  <div slot="other"> Thing 3 </div>
</custom-element>
Brendonbrenk answered 15/1, 2020 at 9:33 Comment(0)
I
0

Addendum to Supersharp his answer:

You can style slotted content with global CSS

div elements (in lightDOM) with a slot attribute are part of the main DOM

Global styles applied to those elements are/maintain applied when slotted inside shadowDOM

customElements.define( 'custom-element', class extends HTMLElement {
  constructor() {
    super()
    this.attachShadow( { mode: 'open' } )
        .innerHTML=`<slot name="thing"></slot>`
                  +`<slot name="other"></slot>`
                  +`<slot></slot>`
  }})
[slot] { background-color: lightblue }
<style id=GlobalStyle>
  [slot]:not([slot="other"]){
    background:green;
  }
</style>

<button onclick=GlobalStyle.disabled=!GlobalStyle.disabled>
TOGGLE GlobalStyle
</button>

<custom-element>
  <div slot="thing"> Thing 1 </div>
  <HR>
  <div slot="thing"> Thing 2 </div>
  <div slot="other"> Thing 3 </div>
  <div slot="none" > Thing 4 </div>
  <b>
    <div> Thing 5 </div>
  </b>
  <div slot="thing"> Thing 6 </div>
</custom-element>

Notes

  • Thing 6 is slotted before Thing 3, because slot thing is defined before slot other
  • Thing 4 is in lightDOM but not slotted, because it does not have a matching slotname
  • All other lightDOM content (especially note the HR) is injected in the unnamed slot
Iconoduly answered 15/1, 2020 at 11:33 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.