javascripthtmlcustom-element

Append a child element to the custom web component in the constructor function


I have defined a custom element in JS. I wanna initialize it in its constructor for example append a template element as its child. but as you know, the browser throws an error that says:

Failed to construct 'CustomElement': The result must not have children

that means I can't append any child element to the custom element in its constructor.

I know that it can be solved if I create a shadow DOM, and then append elements to it, but I don't wanna use shadow DOM in every part of my app; and one another option is to append elements to the custom element in the connectedCallback method, whereas it's invoked every time that the custom element mounts to the DOM, and I think it's not such cool actually. How can I fix that problem without using shadow DOM and connectedCallback method? thanks

the custom component:

class ProductItem extends HTMLElement {
    constructor() {
        super()

        this.appendChild(template.cloneNode(true))
    }
}

customElements.define('product-item', ProductItem)

const template = document.createElement('article')
template.innerHTML = `
    <a href="#">
        <img />
        <section>
            <div>
                <h4></h4>
                <p class="price"></p>
                <p></p>
            </div>
            <button>Add</button>
        </section>
    </a>
`

export { ProductItem }

Solution

  • You can not append in the constructor because the element is NOT in the DOM yet.
    The same happens when you use .createElement("my-element")

    So use the connectedCallback

    Use isConnected property:
    https://developer.mozilla.org/en-US/docs/Web/API/Node/isConnected

    And/Or your own boolean to check (in the connectedCallback) if your append has already run.

    In Vanilla JS there is no other method which runs only once like Lit/Stencil/whatever tools have

    Note: If you see code that does run; it is because the DOM was already parsed, and the constructor ran after DOM was parsed. This usually happens when developers whack on defer or async on scripts that load (and define) the Web Component