javascriptweb-componentshadow-domcustom-element

Unable to nest basic vanilla web component


I have a set of basic web components made out of plain JS. Example:

Account.ts

class Account extends HTMLElement{
   constructor(){
      super();
      this.innerHTML = '<p>My account</p>';
   }
}

customElements.define('account', Account);

Basket.ts

class Basket extends HTMLElement{
   constructor(){
      super();
      this.innerHTML = '<p>My Basket</p>';
   }
}

customElements.define('basket', Basket);

I am trying to create another web component (common) that can be nested in each of the above. For now, lets assume a basic <button> with a click event. I have tried:

CommonButton.ts

class CommonButton extends HTMLElement{
   constructor(){
      super();
      this.innerHTML = '<button onclick="console.log('clicked')">Click Me</button>';
   }
}

customElements.define('common-button', CommonButton);

Account.ts

class Account extends HTMLElement{
   constructor(){
      super();
      this.innerHTML = `
          <p>My Account</p>
          <common-button></common-button>
      `;
   }
}

customElements.define('account', Account);

There are no errors in the browser. I can see in the generated HTML:

<account>
     <p>My Account</p>
     <common-button></common-button>
</account>

However no <button> inside of <common-button>


Solution

    1. Your custom element names are invalid, they must start with a letter, contain at least one -, and have another valid character after that.

    2. It's not allowed to create children in the constructor. Instead, use shadow DOM and create your elements there (which is allowed!).

    That being fixed, here you go:

    class Account extends HTMLElement {
       constructor() {
          super()
            .attachShadow({ mode:'open' })
            .innerHTML = `
              <p>My Account</p>
              <common-button></common-button>
          `;
       }
    }
    
    customElements.define('foo-account', Account);
    
    
    class CommonButton extends HTMLElement {
       constructor() {
          super()
            .attachShadow({ mode:'open' })
            .innerHTML = `<button onclick="console.log('clicked')">Click Me</button>`;
       }
    }
    
    customElements.define('common-button', CommonButton);
    <foo-account></foo-account>