<div class="problem-buttons">
<h2>The Problem: Not Delegating Events Means Rebinding</h2>
<button class="add">Add Button</button>
<button class="btn template">Button</button>
</div>
<div class="jquery-buttons">
<h2>jQuery Event Delegation</h2>
<button class="add">Add Button</button>
<button class="btn template">Button</button>
</div>
<div class="vanilla-js-buttons">
<h2>Vanilla JS Event Delegation</h2>
<button class="add">Add Button</button>
<button class="btn template">Button</button>
</div>
<div class="web-component-buttons">
<h2>Web Component "Event Delegation"</h2>
<button class="add">Add Button</button>
<toggle-button class="template"></toggle-button>
</div>
@import "https://unpkg.com/open-props";
toggle-button {
--wrapperBackground: red;
}
button {
font-weight: var(--font-weight-7);
padding-inline: var(--size-3);
padding-block: var(--size-1);
color: var(--blue-9);
border: var(--border-size-2) solid var(--blue-5);
background-color: transparent;
border-radius: var(--radius-2);
&.active {
background-color: var(--red-5);
}
}
body {
background: var(--gray-9);
font-family: var(--font-sans);
display: grid;
gap: 2rem;
margin: 0;
padding: var(--size-fluid-3);
> div {
background: var(--gray-1);
border-radius: var(--radius-2);
padding: var(--size-fluid-3);
box-shadow: var(--shadow-2);
display: flex;
flex-wrap: wrap;
gap: 1rem;
}
}
h2 {
width: 100%;
margin: 0 0 1rem 0;
}
// General Problem
const originalButtons = document.querySelectorAll(".problem-buttons .btn");
originalButtons.forEach((button) => {
button.addEventListener("click", () => {
button.classList.toggle("active");
});
});
// Old skool jQuery event delegation
$(document).on("click", ".jquery-buttons .btn", function () {
$(this).toggleClass("active");
});
// This is how Vanilla JS event delgation works.
document.querySelector(".vanilla-js-buttons").addEventListener("click", (e) => {
if (e.target.matches(".vanilla-js-buttons .btn")) {
e.target.classList.toggle("active");
}
});
// This is how Web Components work, which sorta naturally has event delegation.
customElements.define(
"toggle-button",
class WebComponentButton extends HTMLElement {
connectedCallback() {
this.innerHTML = `<button class="btn">Button</button>`;
const button = this.querySelector(".btn");
button.addEventListener("click", () => {
button.classList.toggle("active");
});
}
}
);
// Button Duplicator
const addButtons = document.querySelectorAll(".add");
addButtons.forEach((button) => {
button.addEventListener("click", () => {
const templateButton = button.parentElement.querySelector(".template");
const newButton = templateButton.cloneNode(true);
button.parentElement.appendChild(newButton);
});
});
// other ideas: inline click handles like JSX but native.
This Pen doesn't use any external CSS resources.