Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I select the shadow DOM host element only if it is the last-child?

I am looking to select the shadow DOM host element only if it is the last child.

In this example they are all green, I want them to be all red except the last one.

class MyCustomElement extends HTMLElement {
  constructor(){
    super();
    this.attachShadow({mode: 'open'});
    this.shadowRoot.innerHTML = `
      <h5>Element:</h5>
      <slot></slot>
      <style>
        :host {
          color: red;
        }
        :host-context(:last-child) {
          color: green;
        }
      </style>
     `;
  }
}
window.customElements.define('my-custom-element', MyCustomElement);
<div>
  <my-custom-element>first</my-cutom-element>
  <my-custom-element>... more elements</my-cutom-element>
  <my-custom-element>last</my-cutom-element>
</div>

These are all green... I want only the last one to be green.

I have also tried :host:last-child, that does nothing and :host-context(my-custom-element:last-child) also makes them all green.

like image 555
Dustin Poissant Avatar asked Jan 30 '26 17:01

Dustin Poissant


1 Answers

Take the pointers from my other answer: Use CSS selectors like :first-child inside shadow dom

Your elements remain hidden in lightDOM!
any global style you apply (at any time) will be reflected to shadowDOM

customElements.define('my-custom-element', class extends HTMLElement {
  constructor(){
    super()
      .attachShadow({mode: 'open'})
      .innerHTML = `<slot></slot><style>:host { color: red; }</style>`;
  }
});
<div>
  <my-custom-element>first</my-custom-element>
  <my-custom-element>... more elements</my-custom-element>
  <my-custom-element>last</my-custom-element>
</div>

<style>
   div my-custom-element:last-child {
        padding:    .5em;
        background: green;
   }
</style>

Notes:

  • super() returns 'this' (the element itself), so you can chain on it

  • attachShadow returns this.shadowRoot, so you can chain on it

  • the :host-context you mention will not be supported by FireFox and Safari
    see: :host-context not working as expected in Lit-Element web component



Re: comment:

This might be the real answer, but this is a bummer, I thought the entire point of the shadow dom was to be self contained, if i have to write some styles in a global stylesheet to then style something in the shadow dom that doesn't seem like a great deal, no wonder people gravitate towards things like react and vue when web standards are so poor.

Think of it this way. if your my-custom-element where <p> elements; how would a <p> know it is inside the last-child... only by referencing its parent container.

no wonder people gravitate towards things like React and Vue when web standards are so poor.

All Frameworks do exactly the same, they wrap things in containers (be it in regular DOM, shadowDOM, virtual DOM (memory)

Better stated: Frameworks frame your content in containers.. always

The Native W3C standard Custom Element API gives 100% control to use a container or not.

Yes, that means you have to do some scripting/cooking before you can dine.

You have 100% freedom how you want to cook components.

React adds 48 KB (GZipped) to your download, not to mention the whole build process, not to mention it will never work in unison with any other framework, not to mention it doesn't even comply with the ES standard any more.

An extra Custom Element takes you about 15 minutes and maybe 200 bytes

like image 108
Danny '365CSI' Engelman Avatar answered Feb 02 '26 11:02

Danny '365CSI' Engelman