Home > Net >  Is it possible to add elements within a custom element without using `<template>` and template
Is it possible to add elements within a custom element without using `<template>` and template

Time:08-22

I'm trying to create a custom component which can take other HTML Elements, however, it has to be flexible by not having to use <template> and slots templates in the HTML file every time the component is used. Already tried querying after every render by using const children = this.shadow.querySelectorAll('.menu > *') within the connectedCallback() function, but the result is an empty NodeList

class SideMenu extends HTMLElement {
    constructor() {
        super();
        this.shadow = this.attachShadow({mode:'open'});
    }

    render() {
        this.shadow.innerHTML = `
        <style>
          .menu {
            display: flex;
            flex-direction: column;
            height: 100vh;
            padding: 2em;
            width: 33vw;
            gap: 10px;
            background-color: #2C2B2B;
          }
        </style>
        <div >
        </div>
        `;
    }

    connectedCallback() {
        this.render();
    }
}

customElements.define('side-menu', SideMenu);
<side-menu>
    <div>Element1</div>
    <div>Element2</div>
    <div>Element3</div>
    <div>ElementN</div>
</side-menu>

Basically, the custom element has to be able to have any number of elements within, like an unordered list (<ul>) which can have multiple <li> inside.

CodePudding user response:

  • You have a shadowDOM, so don't need an extra div when you style the component with :host

  • you can manually move ligthDOM elements to shadowDOM

  • super() sets AND returns the 'this' scope

  • attachShadow sets AND returns this.shadowRoot

  • append wasn't available in Internet Explorer, ("oldfashioned" devs still use appendChild)
    note it moves the DOM elements from lightDOM to shadowDOM. And if you move Web Components, the connectedCallback will run again (but lightDOM will then be empty) So be aware what you do in the connectedCallback

customElements.define('side-menu', class extends HTMLElement {
    constructor() {
        super().attachShadow({mode:'open'}).innerHTML = `
        <style>
          :host {
            display: flex; flex-direction: column; gap: 10px;
            height: 100vh; width: 33vw;
            padding: 2em;
            background-color: #2C2B2B; color: gold;
          }
        </style>`;
    }

    connectedCallback() {
        this.shadowRoot.append(...this.children);
    }
});
<side-menu>
    <div>Element1</div>
    <div>Element2</div>
    <div>Element3</div>
    <div>ElementN</div>
</side-menu>

  • Related