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' scopeattachShadow
sets AND returnsthis.shadowRoot
append
wasn't available in Internet Explorer, ("oldfashioned" devs still useappendChild
)
note it moves the DOM elements from lightDOM to shadowDOM. And if you move Web Components, theconnectedCallback
will run again (but lightDOM will then be empty) So be aware what you do in theconnectedCallback
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>