Skip to content

Practical Examples

Here are practical, reusable event delegation patterns for common scenarios.

document.querySelector('table').addEventListener('click', (e) => {
const row = e.target.closest('tr');
const action = e.target.closest('button');
if (action?.dataset.action === 'delete') {
row?.remove();
} else if (action?.dataset.action === 'edit') {
console.log('Editing row:', row?.dataset.id);
}
});
document.querySelector('#task-list').addEventListener('click', (e) => {
const btn = e.target.closest('.delete-btn');
if (btn) {
btn.closest('li').remove();
}
});

Form Validation (Events That Don’t Bubble)

Section titled “Form Validation (Events That Don’t Bubble)”
// blur doesn't bubble — use capture phase
document.querySelector('form').addEventListener('blur', (e) => {
if (e.target.matches('input, textarea, select')) {
validateField(e.target);
}
}, true); // Capture phase because blur doesn't bubble
  • Use e.target.closest() to identify the target element
  • Works with data attributes for actions
  • Use capture phase for events that don’t bubble (focus, blur)
  • Single listener handles all current and future elements