Events & Event Listeners
Checking access...
Events are the core of interactivity on the web. An event is a signal that something has happened — a click, a keypress, a form submission, a page load. JavaScript can listen for these events and respond.
Adding an Event Listener
const button = document.querySelector("button");
button.addEventListener("click", function() { console.log("Button was clicked!");});The addEventListener method takes:
- Event type — string like
"click","submit","keydown" - Callback function — runs when the event fires
- Options (optional) —
{ once: true },{ passive: true }, etc.
The Event Object
The callback receives an event object with information about what happened:
button.addEventListener("click", (event) => { console.log(event.type); // "click" console.log(event.target); // the element that was clicked console.log(event.currentTarget); // the element the listener is attached to console.log(event.clientX); // mouse X position relative to viewport console.log(event.clientY); // mouse Y position relative to viewport});Common Event Properties
| Property | Description |
|---|---|
type | Event name ("click", "keydown", etc.) |
target | Element that triggered the event |
currentTarget | Element the listener is attached to |
clientX / clientY | Mouse position relative to viewport |
key | Key pressed (keyboard events) |
code | Physical key code (keyboard events) |
preventDefault() | Cancel default behaviour |
stopPropagation() | Stop event bubbling |
Common Event Types
Mouse Events
element.addEventListener("click", handler); // single clickelement.addEventListener("dblclick", handler); // double clickelement.addEventListener("mousedown", handler); // mouse button pressedelement.addEventListener("mouseup", handler); // mouse button releasedelement.addEventListener("mousemove", handler); // mouse movedelement.addEventListener("mouseenter", handler);// mouse enters elementelement.addEventListener("mouseleave", handler);// mouse leaves elementelement.addEventListener("contextmenu", handler);// right-clickKeyboard Events
document.addEventListener("keydown", (event) => { console.log(`Key pressed: ${event.key}`); // "a", "Enter", "ArrowUp" console.log(`Key code: ${event.code}`); // "KeyA", "Enter", "ArrowUp"
if (event.key === "Enter") { console.log("Enter was pressed"); }
// Check modifier keys if (event.ctrlKey && event.key === "s") { event.preventDefault(); // prevent browser save dialog console.log("Ctrl+S was pressed"); }});
document.addEventListener("keyup", handler); // key releasedTip
Use event.key for the meaning of the key (e.g., "a" vs "A"), and event.code for the physical key position (always "KeyA" regardless of shift/caps lock).
Form Events
const form = document.querySelector("form");const input = document.querySelector("input");
form.addEventListener("submit", (event) => { event.preventDefault(); // stop page reload console.log("Form submitted!");});
input.addEventListener("input", (event) => { console.log(event.target.value); // current input value on every change});
input.addEventListener("change", (event) => { console.log("Value changed and focus lost:", event.target.value);});
input.addEventListener("focus", () => console.log("Input focused"));input.addEventListener("blur", () => console.log("Input lost focus"));Document Events
document.addEventListener("DOMContentLoaded", () => { // DOM is ready — safe to query elements console.log("DOM fully loaded");});
window.addEventListener("load", () => { // Everything loaded including images, styles, scripts console.log("Page fully loaded");});
window.addEventListener("scroll", () => { console.log("Scrolled:", window.scrollY);});
window.addEventListener("resize", () => { console.log("Window resized:", window.innerWidth, "x", window.innerHeight);});Removing Event Listeners
To remove a listener, you need a reference to the same function:
function handleClick(event) { console.log("Clicked!");}
// Addbutton.addEventListener("click", handleClick);
// Remove — must be the same function referencebutton.removeEventListener("click", handleClick);This does not work — anonymous functions are different references:
// ❌ Cannot remove — different function referencesbutton.addEventListener("click", () => console.log("Click"));button.removeEventListener("click", () => console.log("Click")); // no effectOne-Time Events
Use { once: true } for events that should fire only once:
button.addEventListener("click", () => { console.log("This runs only on the first click");}, { once: true });Event Listener Options
element.addEventListener("click", handler, { capture: false, // use capture phase (default: false) once: false, // auto-remove after first invocation passive: false, // if true, indicates handler won't call preventDefault() signal: controller.signal, // AbortSignal to remove listener});Passive listeners improve scroll performance:
// Tell browser this listener won't prevent scrollwindow.addEventListener("touchstart", handler, { passive: true });Delegation Pattern (Setting up listeners on parent elements)
Instead of adding listeners to many individual elements, add one to a parent:
<ul id="list"> <li>Item 1</li> <li>Item 2</li> <li>Item 3</li></ul>// ❌ Inefficient — one listener per itemdocument.querySelectorAll("li").forEach((li) => { li.addEventListener("click", () => console.log(li.textContent));});
// ✅ Efficient — single listener on parentdocument.getElementById("list").addEventListener("click", (event) => { if (event.target.tagName === "LI") { console.log(event.target.textContent); }});Benefits of delegation:
- Works for elements added after the listener is attached
- Uses less memory (one listener vs hundreds)
- Better performance
this in Event Handlers
In a regular function (not arrow), this refers to the element the listener is attached to:
button.addEventListener("click", function() { console.log(this); // the button element console.log(this.textContent);});
// Arrow functions don't have their own `this`button.addEventListener("click", () => { console.log(this); // NOT the button — surrounding lexical scope});Preventing Default Behaviour
link.addEventListener("click", (event) => { event.preventDefault(); // don't navigate console.log("Link clicked but navigation prevented");});
form.addEventListener("submit", (event) => { event.preventDefault(); // don't reload page // handle form with JavaScript instead});
document.addEventListener("contextmenu", (event) => { event.preventDefault(); // disable right-click menu});Triggering Events Programmatically
// Trigger a clickbutton.click();
// Or use the Event constructorconst event = new Event("click");button.dispatchEvent(event);
// With custom dataconst custom = new CustomEvent("userLogin", { detail: { userId: 123, name: "Alice" },});document.dispatchEvent(custom);
// Listen for itdocument.addEventListener("userLogin", (event) => { console.log(event.detail); // { userId: 123, name: "Alice" }});Quick Reference
// Add event listenerelement.addEventListener("event", handler, options);
// Remove event listenerelement.removeEventListener("event", handler);
// Common events"click", "submit", "keydown", "keyup", "input", "change""scroll", "resize", "load", "DOMContentLoaded", "focus", "blur""mouseenter", "mouseleave", "mousemove"
// Useful event propertiesevent.target, event.currentTarget, event.typeevent.key, event.code, event.clientX, event.clientYevent.preventDefault(), event.stopPropagation()Practice Exercises
Key logger: Create a page that displays every key the user presses. Use
document.addEventListener("keydown", ...)and show the key name in a div.Form with live preview: Create a form with a text input. Below it, show a live preview that updates as the user types (use the
inputevent).Click counter: Create a button that counts how many times it was clicked. Use
{ once: true }for a “First Click” log, then keep counting normally. Add a “Reset” button.