I create this simple example (pure JS, not in Vue or React, etc.):
<body>
<script>
(function () {
class MyComponent extends HTMLElement {
constructor() {
super();
const shadowRoot = this.attachShadow({ mode: 'open' });
const template = document.createElement('template');
template.innerHTML = `
<div>
<button>
<slot> <em>left</em> </slot>
</button>
</div>
`;
shadowRoot.append(template.content.cloneNode(true))
shadowRoot.addEventListener('click', (event) => {
// normal event delegation stuff,
const button = event.target.closest('button');
if (!button) return;
// do somthing with button
console.log(button);
});
}
}
customElements.define('my-component', MyComponent);
}());
</script>
<my-component id="myComponent"></my-component>
</body>
Currently it works well.
But, after the slot added:
<my-component id="myComponent"> <span>previous</span> </my-component>
The event delegation code broken, because what I clicked is the Light DOM but Shadow DOM, so, I got null with const button = event.target.closest('button');
Any advise to use event delegation within slot?
If there is any problom with grammar, I am Chinese :) Thank you for reading
The event.composedPath()
output has all the elements the click
Event passed.
Crossing all shadowRoot boundaries in between.
I condensed your code a bit...
Note: The SO snippet console is slow and verbose; check the TOP OF the F12 console (SO snippet could also list sandbox errors there)
<script>
customElements.define('my-component',
class extends HTMLElement {
constructor() {
super()
.attachShadow({mode:'open'})
.innerHTML = `<div>
<button><slot>Left</slot></button>
</div>`;
this.shadowRoot.addEventListener('click', (evt) => {
console.log(evt.composedPath());
});
}
});
</script>
<my-component></my-component>
<my-component>Right</my-component>