I want to make a web component from a <select>
Element. I'm trying to get the <option>
tags supplied by the user to appear in the Shadow DOM.
My component:
let tmpl = document.createElement('template');
tmpl.innerHTML = `
<select placeholder="text">
<slot name="option"></slot>
</select>
`;
class SelectBox extends HTMLElement {
constructor() {
super();
if (!this.shadowRoot) {
this.root = this.attachShadow({mode: 'open'});
this.root.appendChild(tmpl.content.cloneNode(true));
}
}
}
customElements.define('select-box', SelectBox);
HTML:
<select-box>
<option slot="option" value="text">text</option>
</select-box>
What's being rendered is an empty select box. I can see in the console that the element is empty
Which leads me to believe I haven't grasped the process of inserting user elements into the shadow DOM.
It looks like the problem is the option
element that cannot be assigned as slot.
However, since your template is just a select, I wonder why you are not simply extending a select instead and call it a day.
class SelectBox extends HTMLSelectElement {
connectedCallback() {
// in case is not fully parsed yet ...
if (this.selectedIndex < 0)
return setTimeout(() => this.connectedCallback());
this.addEventListener('change', this);
this.parentNode.insertBefore(
document.createElement('p'),
this.nextSibling
);
this.handleEvent();
}
handleEvent() {
this.nextSibling.textContent =
`${this.selectedIndex}: ${this.value}`;
}
}
customElements.define('select-box', SelectBox, {extends: 'select'});
With above class all you need is just the DOM with your options, and you were putting options where these didn't belong anyway, just go full built-in extend.
<select is="select-box">
<option value="first">first</option>
<option value="second">second</option>
</select>
You can see it working live in this code pen.
The less than 1k polyfill and the rest is described in this medium post.
I know this didn't exactly solve your issue, but unless you want to wait for all browsers to fix that at least you know there is a standard/better way to extend built-ins.