Search code examples
web-component

Web Components - wrap child elements


I have a web component which can have children. And on JS seeing it want it to wrap its current children inside of a modal tag (which already has a child).

I currently have:

class Modal extends HTMLElement {
    connectedCallback() {
         // Wrap current children inside of dialog element
    }
}
customElements.define("modal-component", Modal);
<modal-component>
    <p> Lorem impsum </p>
</modal-component>

<!-- I want the logic in connectedCallback() to produce this with the p tag now being wrapped inside dialog -->
<modal-component>
    <dialog>
         <span class="close">&times;</span>
         <p> Lorem impsum </p>
    </dialog> 
</modal-component>

I tried writing this inside of connectedCallback but the value of this.innerHTML is '' even when there are children

this.innerHTML = `<dialog><span class="close">&times;</span>${this.innerHTML}</dialog>`;

I have tried using slots but that feature only seems to cover one to one injection when my Modal component must put multiple children into one slot.

What is the best way of doing this?


Solution

  • With slots you can insert multiple children:

    connectedCallback() {
         this.attachShadow( { mode: 'open' } )
             .innerHTML = `<span class="close">&times;</span>
                     <slot></slot>`
    }
    

    Alternately, if you don't want to use <slot>, you need to make sure that the content of the custom element is parsed when you access the innerHTML property.

    This can be achieved with either setTimeout or requestAnimationFrame, or by defining the Custom Element after the HTML code is parsed (if it's possible):

    <custom-element>...</custome-element>
    <script>
      customElements.define( 'custom-element', ... )
    </script>