🖱️ JavaScript Events — Listeners, Bubbling & Delegation
Master JavaScript events — addEventListener, event bubbling, capturing, delegation and preventDefault. Practical examples and the interview questions companies ask.
Events are how JavaScript reacts to the world — clicks, keypresses, form submits, mouse moves, page loads.
👂 The pattern
element.addEventListener('click', (event) => {
console.log('Clicked!', event.target);
});🌊 Bubbling vs Capturing
When you click a button, the event travels:
- Capture phase: top (window) → target
- Target phase: the clicked element
- Bubble phase: target → top
By default, listeners fire in the bubble phase. Pass { capture: true } for the capture phase.
🎯 Event delegation
Attach ONE listener to a parent and use event.target to detect which child was hit. Crucial for dynamic lists.
🛑 Stopping behavior
event.preventDefault()— stop default action (form submit, link navigation)event.stopPropagation()— stop the event from bubbling further
💻 Code Examples
Event delegation on a list
document.querySelector('#todo-list')
.addEventListener('click', (e) => {
if (e.target.matches('.delete')) {
e.target.closest('li').remove();
}
});Output:
One listener handles deletes for any current AND future <li> in the list.
preventDefault on a form
form.addEventListener('submit', (e) => {
e.preventDefault();
// ... handle via fetch instead
});Output:
Form won't reload the page on submit.
⚠️ Common Mistakes
- Adding a listener inside a loop for every item — leaks memory and slows things down. Use delegation.
- Forgetting to remove listeners on long-lived elements — leads to leaks. Use AbortController for clean removal.
- Confusing event.target (what was clicked) with event.currentTarget (where the listener is attached).
🎯 Interview Questions
Real questions asked at top product and service-based companies.
Q1.What's event bubbling?Beginner
After firing on the target, an event travels up through its ancestors (parent → grandparent → … → window), triggering listeners along the way. This lets parents react to child events.
Q2.What is event delegation?Intermediate
Attaching a single listener to a common ancestor and inspecting `event.target` to handle child events. Reduces memory and works with elements added later dynamically.
Q3.Difference between event.target and event.currentTarget?Intermediate
target = the actual element clicked. currentTarget = the element the listener is attached to. In delegation they differ; otherwise they match.
Q4.Difference between preventDefault and stopPropagation?Intermediate
preventDefault cancels the browser's default behavior (form submit, link navigation, scroll). stopPropagation stops the event from bubbling/capturing to other listeners. They're independent.
Q5.How do you remove an event listener cleanly?Advanced
Either keep a named reference (`el.removeEventListener('click', handler)`) or use AbortController: `el.addEventListener('click', fn, { signal: ctrl.signal })` and call `ctrl.abort()` to remove all at once.
🧠 Quick Summary
- addEventListener is the modern API — supports multiple listeners.
- Events bubble by default; capture phase is opt-in.
- Delegation = one parent listener for many children.
- preventDefault blocks default behavior; stopPropagation blocks bubbling.
- Use AbortController for clean teardown.