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?

admcfajn
  • 2,013
  • 3
  • 24
  • 32
Jackie
  • 21,969
  • 32
  • 147
  • 289
  • 1
    `[slot="thing"]{ border: 2px dashed #f00; }` [Attribute selectors](https://developer.mozilla.org/en-US/docs/Web/CSS/Attribute_selectors) – admcfajn Jan 15 '20 at 03:28
  • So would thing be like `:head[slot="thing"]` given shadow dom? – Jackie Jan 15 '20 at 03:29
  • 1
    I'm not sure about the web-component implementation... I thought you were just looking for the css-selector... `slot[name="thing"]` maybe? – admcfajn Jan 15 '20 at 03:35
  • 1
    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=...]`. – Sheraff Jan 15 '20 at 12:05
  • Sorry meant host – Jackie Jan 15 '20 at 13:40

2 Answers2

7

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>
Supersharp
  • 29,002
  • 9
  • 92
  • 134
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
Danny '365CSI' Engelman
  • 16,526
  • 2
  • 32
  • 49