<div class=expander>
<button aria-expanded=false>Expand</button>
<!-- Some other stuff here -->
</div>
And you have some JS that handles the expander's behaviour: for (const expander of document.querySelectorAll('.expander')) {
const btn = expander.querySelector('button');
btn.addEventListener('click', () => {
btn.ariaExpanded = 'true';
});
}
This will work fine for `.expander` divs that are already in the page when the event handler is set up. But suppose you dynamically load new expander divs, what then? Your event handler is not going to retroactively set up their click listeners too.Custom elements solve exactly this problem. You can now do:
<expander-elem>
<button aria-expanded=false>Expand</button>
<!-- Some other stuff here -->
</expander-elem>
And then set up the listener: customElements.define('expander-elem', class extends HTMLElement {
connectedCallback() {
const btn = this.querySelector('button');
btn.addEventListener('click', () => {
btn.ariaExpanded = 'true';
});
}
});
And the browser will ensure that it always sets up the listeners for all of the expanders, no matter whether they are loaded on the page initially or dynamically injected later. Without this you would have had to jump through a bunch of hoops to ensure it. This solves the problem elegantly.