Events & Event Handling
Adding Event Listeners
const btn = document.querySelector("#myBtn");
// Method 1: addEventListener (BEST PRACTICE)
btn.addEventListener("click", function(event) {
console.log("Button clicked!");
console.log(event);
});
// Method 2: Arrow function
btn.addEventListener("click", (e) => {
e.preventDefault();
console.log(e.target);
});
// Method 3: Named function (easy to remove)
function handleClick(e) {
console.log("Clicked");
}
btn.addEventListener("click", handleClick);
btn.removeEventListener("click", handleClick); // remove
// Method 4: Inline HTML (AVOID)
// <button onclick="handleClick()">Click</button>
Common Events
| Category | Events |
|---|---|
| Mouse | click, dblclick, mousedown, mouseup, mousemove, mouseover, mouseout, mouseenter, mouseleave |
| Keyboard | keydown, keyup, keypress (deprecated) |
| Form | submit, change, input, focus, blur, reset |
| Window | load, DOMContentLoaded, resize, scroll, unload |
| Drag | drag, dragstart, dragend, dragover, drop |
| Touch | touchstart, touchmove, touchend |
| Clipboard | copy, paste, cut |
The Event Object
document.addEventListener("click", function(event) {
event.target; // element that was clicked
event.currentTarget; // element the listener is attached to
event.type; // "click"
event.clientX; // mouse X in viewport
event.clientY; // mouse Y in viewport
event.key; // key pressed (for keyboard events)
event.altKey; // true if Alt held
event.ctrlKey; // true if Ctrl held
event.shiftKey; // true if Shift held
event.preventDefault(); // prevent default browser action
event.stopPropagation(); // stop bubbling
});
Event Bubbling and Capturing
// BUBBLING (default): propagates UPWARD from target
// inner click → fires on inner, then parent, then grandparent...
// CAPTURING: propagates DOWNWARD
// addEventListener 3rd arg = true enables capturing
document.querySelector(".outer").addEventListener("click", () => {
console.log("outer");
}, true); // capturing phase
document.querySelector(".inner").addEventListener("click", () => {
console.log("inner");
});
// Click on .inner: logs "outer" then "inner" (capturing first)
stopPropagation vs preventDefault
// stopPropagation: prevents event from bubbling up
div.addEventListener("click", (e) => {
e.stopPropagation(); // parent won't receive this event
});
// stopImmediatePropagation: also prevents other listeners on same element
div.addEventListener("click", (e) => {
e.stopImmediatePropagation();
});
// preventDefault: blocks browser's default action
link.addEventListener("click", (e) => {
e.preventDefault(); // link won't navigate
});
form.addEventListener("submit", (e) => {
e.preventDefault(); // form won't submit
});
Event Delegation
Instead of adding listeners to many elements, add one listener to a parent.
// BAD: Adding listener to each button (100 buttons = 100 listeners)
document.querySelectorAll(".btn").forEach(btn => {
btn.addEventListener("click", handleClick);
});
// GOOD: Event delegation
document.querySelector("#button-container").addEventListener("click", (e) => {
if (e.target.matches(".btn")) {
handleClick(e);
}
// Or with data attributes
if (e.target.dataset.action === "delete") {
deleteItem(e.target.dataset.id);
}
});
Custom Events
// Create a custom event
const customEvent = new CustomEvent("userLogin", {
detail: { userId: 42, role: "admin" },
bubbles: true,
cancelable: true
});
// Dispatch the event
document.dispatchEvent(customEvent);
// Listen for it
document.addEventListener("userLogin", (e) => {
console.log(e.detail.userId); // 42
});
Once, Passive, and Signal Options
// once: auto-remove after first trigger
btn.addEventListener("click", handler, { once: true });
// passive: improves scroll performance
window.addEventListener("scroll", handler, { passive: true });
// AbortController: remove multiple listeners at once
const controller = new AbortController();
btn.addEventListener("click", handler, { signal: controller.signal });
document.addEventListener("keydown", handler, { signal: controller.signal });
controller.abort(); // removes all at once
MCQ — Events
Q1: What is event bubbling?
A) An event that fires multiple times B) An event that propagates from the target element upward through ancestors ✅ C) An event that propagates downward from document to target D) When two events fire simultaneously
Answer: B
Q2: What does event.preventDefault() do?
A) Stops event bubbling B) Removes the event listener C) Prevents the browser's default action for that event ✅ D) Stops all other listeners from running
Answer: C
Q3: What is event delegation?
A) Assigning multiple events to one element B) Attaching one listener to a parent to handle events from child elements ✅ C) Delegating events to the window object
Answer: B
Q4: What is the difference between event.target and event.currentTarget?
A) They are the same
B) target is the element clicked; currentTarget is the element with the listener ✅
C) currentTarget is the element clicked; target is the element with the listener
Answer: B
Q5: How do you run an event listener only ONCE automatically?
A) addEventListener("click", fn, { once: true }) ✅
B) addEventListener("click", fn) then call removeEventListener after
C) Both A and B work
Answer: C — Both work, but { once: true } is more concise.
Q6: Which event fires when ALL resources (images, scripts) finish loading?
A) DOMContentLoaded
B) ready
C) load ✅
D) complete
Answer: C — DOMContentLoaded fires when DOM is ready but before images/styles finish.
Q7: What does stopPropagation() do?
A) Prevents default browser action B) Removes all event listeners C) Stops the event from bubbling up (or capturing down) ✅ D) Cancels all pending events
Answer: C