I have two minimal HTMLElements: an AppRoot
and a SubElement
. The innerHTML of the elements is generated via lit-html's render
and html
templating functions.
AppRoot
's HTML template is a div
with two paragraphs in it: one displays the text of a message
attribute, the other one instantiates a SubElement
and passes it a string.
The SubElement
's HTML template is solely the passed string.
I would expect the rendered HTML to look like this:
<div>
<p>AppRoot's message</p>
<p>The string passed to SubElement</p>
</div>
But it is in fact only the SubElement's rendered template:
The string passed to SubElement
Why does the SubElement's template substitute AppRoot's template when it's rendered? I've experimented with changing the tags (enclosing with divs, paragraphs), but to no avail.
You can find the source code below.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<script src="./index.js" type="module"></script>
<app-root></app-root>
</body>
</html>
import { render, html } from './node_modules/lit-html/lit-html.js';
class SubElement extends HTMLElement {
constructor(message) {
super();
this.message = message;
}
connectedCallback() {
this.innerHTML = render(this.template(), document.body);;
}
template() {
return html`
${this.message}
`;
}
}
customElements.define('sub-element', SubElement);
class AppRoot extends HTMLElement {
constructor() {
super();
this.message = "I am root!";
}
connectedCallback() {
this.innerHTML = render(this.template(), document.body);
}
template() {
return html`
<div>
<p>${this.message}</p>
<p>${new SubElement("I am not root!")}</p>
</div>
`;
}
}
customElements.define('app-root', AppRoot);
The second parameter of render
is the container where the template should be rendered at. Each component is currently rendering the template results to the document body and overwriting previously rendered results.
connectedCallback() {
this.innerHTML = render(this.template(), document.body);
}
You should look into using shadow DOM or render within the component itself.
connectedCallback() {
render(this.template(), this);
}