An event is something that happens on the page — a click, a key press, a form submission, a mouse hover. Event listeners let you run code when these events occur.
Every event handler receives an event object with details about what happened:
Copy
button.addEventListener("click", (event) => { console.log(event.type); // "click" console.log(event.target); // The element that was clicked console.log(event.clientX); // Mouse X position console.log(event.clientY); // Mouse Y position});
Some elements have built-in behaviors. preventDefault() stops them:
Copy
// Stop a form from reloading the pageform.addEventListener("submit", (e) => { e.preventDefault(); // Don't reload! // Handle submission with JavaScript instead});// Stop a link from navigatinglink.addEventListener("click", (e) => { e.preventDefault(); // Don't navigate! // Do something else instead});
Forms reload the page on submit by default. You’ll almost always want e.preventDefault() when handling forms with JavaScript. This is the single most common gotcha in form handling.
Instead of adding a listener to every list item, add one listener to the parent and check event.target:
Copy
// ❌ Adding a listener to every item (slow for many items)document.querySelectorAll(".user-card").forEach(card => { card.addEventListener("click", () => { console.log("Card clicked"); });});// ✅ One listener on the parent (event delegation)document.querySelector("#user-list").addEventListener("click", (e) => { const card = e.target.closest(".user-card"); if (card) { console.log("Card clicked:", card.dataset.userId); }});
Benefits of event delegation:
Works for elements added after the listener is set up (dynamically created elements)
One listener instead of hundreds — better performance
No need to re-attach listeners when the list changes
element.closest(selector) walks up the DOM tree from the clicked element and returns the first ancestor matching the selector. It’s essential for event delegation — it finds the container you care about, even if the user clicked a child element inside it.
To remove a listener, you need a reference to the same function:
Copy
function handleClick() { console.log("Clicked!");}// Addbutton.addEventListener("click", handleClick);// Removebutton.removeEventListener("click", handleClick);
Copy
// ❌ This doesn't work — different function referencesbutton.addEventListener("click", () => console.log("Click!"));button.removeEventListener("click", () => console.log("Click!")); // Not the same function// ✅ Use a named functionfunction handler() { console.log("Click!"); }button.addEventListener("click", handler);button.removeEventListener("click", handler); // Same function reference