Skip to main content

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

CategoryEvents
Mouseclick, dblclick, mousedown, mouseup, mousemove, mouseover, mouseout, mouseenter, mouseleave
Keyboardkeydown, keyup, keypress (deprecated)
Formsubmit, change, input, focus, blur, reset
Windowload, DOMContentLoaded, resize, scroll, unload
Dragdrag, dragstart, dragend, dragover, drop
Touchtouchstart, touchmove, touchend
Clipboardcopy, 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) loadD) complete

Answer: CDOMContentLoaded 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