Get value from selected option in web component
I'm trying to get the value of the selected option, so when someone uses my web component, they can access it. I think the problem is related to shadow root
__createOptions() {
const SELECT = this.shadowRoot.querySelector('select');
SELECT.addEventListener('change', event => {
this.value= event.target.value;
});
this.shadowRoot.addEventListener('slotchange', () => {
const OPTION = this.querySelector('option');
if (OPTION) {
SELECT.append(OPTION);
}
});
}
render() {
return html`
<div class="selectWrapper">
<select id="typeDropdown"></select>
</div>
<slot></slot>
`;
}
<wc-select value="">
<option value="1">Option 1</option>
<option value"2">Option 2</option>
<option value="3">Option 3</option>
</wc-select>
My review is too fast.
<SLOTs>
cannot be positioned like "normal" DOM elements
(like many) you're running into the trap of thinking the slotted content
is MOVED to ShadowDOM<slots>
It is not .
The slotted content is only REFLECTED in shadowDOM, it's still invisible! in lightDOM
You can't access the reflected content using or ... because it doesn't exist (in ShadowDOM). It's still in lightDOM..querySelector
.children[]
For the same reason you need to style the trough content in the lightDOM:
use CSS selectors inside the shadow dom, eg: first-child
Append lightDOM <OPTIONs>
to shadowDOM<SELECT`>
1. You can move them from lightDOM to shadowDOM:
let select = this.shadowRoot.querySelector('select');
let host = this.shadowRoot.getRootNode().host;
let options = host.querySelectorAll('option');
select.append(...options);
#1 is the easiest as it does n't require anything <slots>
in shadowDOM
2. You are on the right trackslotchange
Came across an event that requires a (named/unnamed) event in the<slot></slot>
shadowDOM template .
You can find lightDOM nodes at:
Note that this will get you all nodeTypes including nodes ,text
Because of newlines and spaces <my-element>
in innerHTML !
<my-element>
<option>Grow up</option>
<option>Learn React</option>
<option>Learn Lit</option>
<option>Forget W3C standard Custom Elements API</option>
<H1 slot=title>My Never Todo List</hH>
</my-element>
Fortunately, <SELECT>
it doesn't care, so you can dump assignedNodes
directly .
this.shadowRoot.addEventListener('slotchange', (evt) => {
if (!evt.target.name) { // only for unnamed slot
this.shadowRoot.querySelector('select')
.append(...evt.target.assignedNodes());
}
});
Notice! The reflected unnamed slot, reflected<options>
to
<H1 slot=title>
<slot name=title>
(they should have named them reflection instead of slot )
Click show code snippet for full code
customElements.define("my-element", class extends HTMLElement {
connectedCallback() {
let template = document.getElementById(this.nodeName);
this.attachShadow({
mode: 'open'
}).append(template.content.cloneNode(true));
this.shadowRoot.addEventListener('slotchange', (evt) => {
if (!evt.target.name) { // only for unnamed slot
let select = this.shadowRoot.querySelector('select');
select.append(...evt.target.assignedNodes());
}
});
}
})
<template id=MY-ELEMENT>
<style>
:host {
display: block;
}
select{
font-size:1.5em;
}
</style>
<slot name=title></slot>
<select multiple>
</select>
<slot></slot>
</template>
<my-element>
<option>Grow up</option>
<option>Learn React</option>
<option>Learn Lit</option>
<option>Forget W3C standard Custom Elements API</option>
<h1 slot=title>My Never Todo List</h1>
</my-element>
JSFiddle playground with two options : https://jsfiddle.net/CustomElementsExamples/v2f9zmu5/
More slots-related answers can be found via a StackOverflow search: Custom Element Slots