SYP Start Your Path

Module 2: Events

Event Listeners

let button = document.querySelector("#myBtn");

button.addEventListener("click", function () {
  console.log("Button was clicked!");
});

button.addEventListener("click", () => console.log("Clicked!"));

function handleClick() {
  console.log("Handled");
}
button.addEventListener("click", handleClick);
button.removeEventListener("click", handleClick);

Multiple listeners can be attached to the same element for the same event — all of them run.

Bubbling, Capturing & Delegation

When you click a child element, the click event doesn't just fire there — it travels through the DOM tree in two phases:

Capturing phase: document → ... → target (top-down)
Target phase: the element actually clicked
Bubbling phase: target → ... → document (bottom-up, the default)
outer.addEventListener("click", () => console.log("Outer"));
inner.addEventListener("click", () => console.log("Inner"));
// Clicking "inner" logs: "Inner", then "Outer" (bubbles up)

// Listen during the capturing phase instead, with a third argument
outer.addEventListener("click", () => console.log("Outer capturing"), true);

// Stop an event from bubbling further
inner.addEventListener("click", (event) => event.stopPropagation());

Event delegation uses bubbling on purpose: instead of attaching a listener to every item in a list, attach ONE listener to their shared parent and check which child triggered it. Efficient, and automatically works for items added later.

let list = document.querySelector("ul");
list.addEventListener("click", function (event) {
  if (event.target.tagName === "LI") {
    console.log("You clicked:", event.target.textContent);
  }
});

Keyboard, Mouse & Touch Events

// Mouse
el.addEventListener("click", fn);
el.addEventListener("dblclick", fn);
el.addEventListener("mouseover", fn);
el.addEventListener("mouseout", fn);

// Keyboard
input.addEventListener("keydown", (e) => console.log(e.key)); // e.g. "Enter", "a"
input.addEventListener("keyup", fn);

// Touch (mobile)
el.addEventListener("touchstart", fn);
el.addEventListener("touchmove", fn);
el.addEventListener("touchend", fn);

// Every handler receives an event object with useful details
button.addEventListener("click", function (event) {
  console.log(event.type);   // "click"
  console.log(event.target); // the exact element clicked
});

Forms & Validation

let form = document.querySelector("form");

form.addEventListener("submit", function (event) {
  event.preventDefault(); // stops the default page-reload behavior

  let email = document.querySelector("#email").value;
  if (!email.includes("@")) {
    console.log("Please enter a valid email");
    return;
  }
  console.log("Form submitted:", email);
});

// HTML also provides built-in validation attributes (checked before JS even runs)
// <input type="email" required minlength="5">

input.addEventListener("input", (e) => {
  console.log("Current value:", e.target.value); // fires on every keystroke
});