3

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.

Dustin Poissant
  • 3,201
  • 1
  • 20
  • 32

1 Answers1

1

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:



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

Danny '365CSI' Engelman
  • 16,526
  • 2
  • 32
  • 49
  • 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. – Dustin Poissant May 02 '20 at 03:38
  • Im thinking ill just write some javascript that generates inline styles because im not going to include this in a global stylesheet to ship to all pages when 99% of my pages wont even have a custom element on it, and im not going to write a style tag in the HTML document itself after using the custom element. id rather just do everything in one JS file. – Dustin Poissant May 02 '20 at 03:40
  • added reply in answer – Danny '365CSI' Engelman May 02 '20 at 10:52