When I tried to append slot child on my component on LitElement, It doesn't work and didn't accept to create it.
render() {
return html `<div class="wizard-container ${this.className}"></div>`;
}
firstUpdated() {
let wizardContainer = this.shadowRoot.querySelector('.wizard-container');
for (let i = 0; i < this.steps; i++) {
let slot = document.createElement('SLOT');
slot.setAttribute('name', 'step_' + (i + 1))
wizardContainer.appendChild(slot);
};
}
While I personally don't recommend you to create slots dynamically for a web component you can achieve it, you just need to keep the creation code in the render function
For example, you can create an array out of your steps
variable and iterate it using the map
function to create the slots like this:
render() {
return html`<div class="wizard-container ${this.className}">
${Array.from({ length: this.steps }, (v, k) => k).map(
item =>
html`<slot name="step_${item}"><div>Default content ${item}</div></slot>`
)}
</div>`;
}
And then use your component like this:
<my-element steps="3">
<div slot="step_1">Custom content</div>
</my-element>
Which would result in something like:
Default content 0 Custom content Default content 2
As for the reason why your previous code wasn't working like you expected, LitElement for the most part expects you to keep the code related to templating in the render function as anything you add using appendChild
or similar DOM functions will get "deleted" the next time the component updates so you'd have to append it after every update by yourself
By adding the slots directly in the render method, you guarantee they don't get deleted in unexpected ways