Course topics

By WebNest Studio Engineering Team

JavaScript Tutorial

Events and Event Handling

Events are how the browser tells your JavaScript that something happened — a click, a keypress, a page load, a form submission, a network response. Almost all interactivity on the web is built by listening for events and reacting to them.

Understanding not just how to attach a listener, but how events travel through the DOM (capturing and bubbling), unlocks powerful patterns like event delegation that make code both simpler and more efficient.

Why it matters

A web page does nothing until the user acts: clicks, types, scrolls, submits. Events are how code responds. Event delegation, where one listener on a parent handles all its children, is how lists of any length are handled efficiently, and how events travel through the page is a standard interview question.

addEventListener and the Event Object

element.addEventListener('click', handler) registers a function to run whenever that event fires on that element. Unlike the older onclick = handler style, addEventListener allows multiple listeners on the same event without overwriting each other, and it accepts an options object ({ once: true, capture: true, passive: true }). Every handler receives an event object describing what happened — event.target (the actual element that triggered it), event.type, event.preventDefault() (stops the default browser action, like following a link), and event.stopPropagation() (stops the event from continuing to travel).

Bubbling and Capturing

When an event fires on an element, it doesn't just affect that element — it travels through the DOM tree in two phases. The capturing phase goes from the document down to the target element; the bubbling phase then goes back up from the target to the document. By default, addEventListener listens during the bubbling phase; passing { capture: true } listens during capturing instead. This is why a click on a button inside a div also triggers click listeners on that div and on document, unless stopPropagation() is called.

Event Delegation

Instead of attaching a listener to every individual list item, button, or row (which is wasteful and doesn't work for elements added later), you attach a single listener to a stable parent element and use event.target to figure out which child was actually interacted with. This relies entirely on bubbling and is a standard performance and maintainability pattern for dynamic lists.

  • Fewer listeners registered — better memory and setup performance for large lists.
  • Automatically works for elements added to the DOM later, since the listener lives on the parent.
  • Requires checking event.target (or event.target.closest(selector)) to identify the actual element clicked.

Examples

Basic click listener with the event object

JavaScript
const button = document.querySelector('#save-btn');

button.addEventListener('click', (event) => {
  event.preventDefault();
  console.log('Clicked element:', event.target.tagName);
  console.log('Event type:', event.type);
});
Output
Clicked element: BUTTON
Event type: click

Event delegation on a list, handling clicks on any current or future item

JavaScript
const list = document.querySelector('#task-list');

list.addEventListener('click', (event) => {
  const item = event.target.closest('.task');
  if (!item) return; // click was on the list itself, not an item

  item.classList.toggle('done');
  console.log('Toggled:', item.textContent);
});

// Even an item added later, e.g. list.appendChild(newLi),
// is handled correctly because the listener is on 'list', not each item.
Output
Toggled: Buy milk and eggs

Common Mistakes

  • Attaching a separate listener to every list item and forgetting to attach one to items added dynamically afterward — event delegation solves this by listening on the parent.
  • Confusing event.target (the exact element the event originated on) with event.currentTarget (the element the listener is actually attached to) inside a delegated handler.
  • Forgetting to call event.preventDefault() on a form submit handler, causing an unwanted full-page reload/navigation.
  • Assuming stopPropagation() also prevents the default browser action — it only stops the event from bubbling/capturing further; preventDefault() is the one that cancels default behavior.

Exercise

Count clicks on the button and show the count in the paragraph as Clicked 1 times, Clicked 2 times and so on. Attach a single listener to main and act only when the element that was clicked is the button.

Expected result: clicking the button updates the paragraph; clicking the heading or the paragraph does nothing.

JavaScript · starter code
// The page contains: <main> with an <h1>, a <p> and a <button>

let count = 0;
const main = document.querySelector("main");
const output = document.querySelector("p");

// TODO: one click listener on main that reacts only to clicks on the button
Show hints
  • event.target is the element that was actually clicked.
  • event.target.matches("button") tests whether that element is a button.
Show solution
JavaScript · solution
// The page contains: <main> with an <h1>, a <p> and a <button>

let count = 0;
const main = document.querySelector("main");
const output = document.querySelector("p");

main.addEventListener("click", (event) => {
  if (!event.target.matches("button")) return;
  count += 1;
  output.textContent = "Clicked " + count + " times";
});

Quick quiz

1. What is event bubbling?

  • A. An event being cancelled
  • B. An event firing twice
  • C. An event travelling from the target element up through its ancestors
  • D. An event travelling from the document down to the target
Show answer

C. The downward journey is the capturing phase, which listeners can opt into.

2. What does event.preventDefault() do?

  • A. Stops the event from reaching other elements
  • B. Removes the listener
  • C. Reloads the page
  • D. Stops the browser's default action, such as following a link or submitting a form
Show answer

D. Stopping propagation is a separate method, event.stopPropagation().

3. Why is addEventListener preferred to an onclick attribute in the HTML?

  • A. It keeps behaviour out of the markup and allows several listeners on one element
  • B. It is the only one that works
  • C. It runs faster
  • D. It prevents bubbling
Show answer

A. Listeners can also be removed again with removeEventListener.

Interview questions

What is event delegation and why use it?

Show answer

Instead of attaching a listener to every child element, one listener is attached to a common ancestor. Because events bubble, a click on any child reaches the ancestor, where event.target identifies which child was clicked. It uses one listener in place of hundreds, and it works for children added later, since no listener has to be attached to them. It is the standard way to handle lists and tables.

What is the difference between event.target and event.currentTarget?

Show answer

event.target is the element on which the event originated, the one the user actually clicked. event.currentTarget is the element whose listener is currently running. With a listener on a list and a click on one of its items, target is the item and currentTarget is the list. They are the same only when the listener is on the element that was clicked.

Key Points to Remember

  • addEventListener supports multiple handlers per event and accepts options like { once: true }.
  • Events travel through capturing (top-down) then bubbling (bottom-up) phases; listeners default to the bubbling phase.
  • Event delegation attaches one listener to a parent and uses event.target to identify the actual source, which scales to dynamic content.
  • preventDefault() cancels default browser behavior; stopPropagation() stops the event from traveling further.

Practice in the playground

Write and run your own code for this topic, or start from the exercise or an example. Shows a live preview of your HTML, CSS and JavaScript. Your code for each topic is kept in this browser.

Run the examples

Change an input, predict the result, then compare it with the output. Explain why the result changes.

WebNest Studio

Written by

WebNest Studio Engineering Team

Practical lessons from developers working with Java, Python, React, databases and production systems.

Led by Vansh Duggal, Founder, WebNest Studio · Full-stack & software engineering