Events: Making Pages React to People
18 minBeginnerHTML · CSS · JS
In this lesson
- ▸Attach listeners with
addEventListenerforclick,inputandsubmit - ▸Read information from the event object and stop a form from reloading the page
- ▸Explain event bubbling and use it to handle many elements with one listener
The big idea
An event listener says: "when this happens to that element, run this function". Your code stops running top-to-bottom once and starts waiting for the user.
Last lesson your script changed the page once, as soon as it loaded. Real interfaces wait: nothing happens until someone clicks, types or submits. Each of those actions fires an event, and you can listen for it.
const button = document.querySelector("#like");
button.addEventListener("click", function () {
console.log("Clicked!");
});
// The same with an arrow function:
button.addEventListener("click", () => console.log("Clicked!"));Bug: calls the function immediately
button.addEventListener("click", sayHi());Correct: hands the function over for later
button.addEventListener("click", sayHi);With () you run sayHi right now and pass its result (usually undefined). Without (), the browser calls it on every click.
The event object
The browser passes your function an event object describing what happened. The most useful property is event.target: the element the event happened on. For text boxes, event.target.value is what's currently typed.
const message = document.querySelector("#message");
// "input" fires on every keystroke, paste or delete
message.addEventListener("input", (event) => {
console.log(event.type); // "input"
console.log(event.target.value.length); // characters so far
});
document.addEventListener("keydown", (event) => {
console.log(event.key); // "a", "Enter", "Escape", …
});Forms and preventDefault
When a form is submitted, the browser's default action is to send the data and load a new page — wiping out your JavaScript state. To handle the form yourself, listen for submit on the form (not the button, so pressing Enter works too) and call event.preventDefault().
const form = document.querySelector("#guest-form");
form.addEventListener("submit", (event) => {
event.preventDefault(); // "don't do your default thing — I've got this"
const name = document.querySelector("#guest-name").value.trim();
console.log("Welcome, " + name);
});In WANCode's preview, a forgotten preventDefault() won't reload anything — the preview blocks it and prints a hint in the Console. On a real site the page would reload.
Event bubbling
An event doesn't stay on the element you clicked. After it fires there, it bubbles up through every parent — the list, the section, the body, the document — and any listener along the way runs too.
// One listener on the <ul> handles clicks on ANY <li> inside it —
// even items added later. This is called event delegation.
list.addEventListener("click", (event) => {
const li = event.target.closest("li"); // the <li> that was clicked (or null)
if (li) {
li.classList.toggle("done");
}
});
// (Rarely needed) stop the event from bubbling further:
// event.stopPropagation();Under Step 1, listen for click on #like. Each click should:
1. add 1 to likes,
2. show the new number in #likes,
3. give the button the class liked (it turns pink).
Checks
- Each click adds 1 to #likes
- A click gives the button the class liked
Check understanding
What you learned
- ✓
element.addEventListener("type", fn)runsfnevery time that event happens — passfn, don't call it. - ✓The event object tells you what happened:
event.target,event.target.value,event.key. - ✓Handle forms on
submitand callevent.preventDefault()to stay on the page. - ✓Events bubble up, so one listener on a parent can handle all its children (delegation).
Console output from your code appears here.