javascripthtmlweb-component

How to create custom elements in HTML on demand?


I am curretly adding some customm elements for an inhouse framework , however I noticed that we are getting all the elements on an index file to use them inside the html.

Do you know a better way to do this ? like a lazy instantiation.

current code :

customElements.define('element-a', ElementA);
customElements.define('element-b', ElementB);
customElements.define('element-c', ElementC);
customElements.define('element-d', ElementD);
customElements.define('element-f', ElementF);
....

Solution

  • You can find custom elements, hide them, load classes async and upgrade elements:

    class CustomElement extends HTMLElement{
      connectedCallback() {
        const template = document.createElement("template")
        template.innerHTML = /* html */ `
          <style>
            :host {
              background-color: yellow;
            }
          </style>
    
          <slot></slot>
        `
        const shadowRoot = this.attachShadow({ mode: "open" })
        shadowRoot.appendChild(template.content.cloneNode(true))
      }
    }
    
    const promises = {};
    
    // you can also traverse DOM tree, could be faster
    document.querySelectorAll('*').forEach(async el => {
      if(el.tagName.includes('-')){
    
        let display;
        [{display}, el.style.display] = [el.style, 'none'];
        const tag = el.tagName.toLowerCase();
    
        const name = tag.replace(/^\w|-\w/gd, m => m.at(-1).toUpperCase());
        
        // use something like import() to load a custom element class
        let defined = true;
        const factory = await (promises[name] ??= (
          defined = false,
          new Promise(r => setTimeout(() => r(eval(name)), 200))
        ));
        
        defined || customElements.define(tag, factory),
        
        el.style.display = display;
      }
    });
    <custom-element>Custom Element</custom-element><br/>
    <custom-element>Second Element</custom-element>