Listening & Responding
Advanced · 18 min read · ▶ live playground · ✦ checkpoint
Static DOM scripts run once and leave the page changed. Events let the page keep listening after that first script finishes, so a click, tap, key press, or browser signal can call your JavaScript at the moment it happens.
In practice, interactive pages start with one method: addEventListener. You give an element an event name and a callback function, and the browser calls that function later with an event object.
Listeners are callbacks for page moments
A listener is a callback registered for a named event. The most common first event is "click":
button.addEventListener("click", handleClick);
Read that as: "when this button receives a click event, call handleClick." The function is not called now. You pass the bare function value, just like the callback lessons in Section 5 and the async callback lessons in Section 12.
Try the counter. Click Add one, pause the listener, click Add one again, then resume it.
removeEventListener is deliberately strict: it needs the same event name and the same function reference you originally registered. In the playground, handleAddClick is a named function, so both addEventListener and removeEventListener can point at the same function object.
This is why anonymous arrows are fine for tiny one-way listeners, but awkward for later cleanup. If you write button.addEventListener("click", () => { count += 1; });, there is no saved function reference to pass to removeEventListener later. Creating a new arrow with the same code does not help; it is a different function object.
The event object tells you what happened
Every listener receives an event object as its first argument. That object describes the moment that just happened: what kind of event it was, where it started, which listener is currently running, and event-specific details.
Two fields matter immediately:
event.targetis the exact element where the event started.event.currentTargetis the element whose listener is running right now.
Click the button text, the small badge, and the empty space inside the card. The listener is on the card, but the exact target changes depending on where the click begins.
The click reaches the card listener even when it starts on a child element inside the card. The next lesson explains the route events take through the DOM tree. For now, keep the distinction simple: target answers "where did it start?" and currentTarget answers "which listener is running?"
Different event types carry different extra fields. Click events commonly use type, button, clientX, clientY, and modifier keys like shiftKey or altKey. Keyboard and pointer events get their own deeper lesson in 15.4, so do not try to memorize every field now. Learn to inspect the event object and read the fields that answer the current UI question.
Options change the listener contract
The third argument to addEventListener can be an options object. Three options are worth learning early because they make listener lifetime and browser defaults explicit.
once: true means "run this listener one time, then remove it automatically." signal connects the listener to an AbortController, the same cleanup idea you saw in async cancellation: abort the controller, and every listener registered with that signal is removed. passive: true means "this listener promises it will not call preventDefault()." That promise is most useful for scroll-related events because the browser can keep scrolling without waiting for your JavaScript. This lesson uses a click so you can verify the option shape; the important rule is the promise, not the button.
Click Claim bonus twice: the text changes once because the browser removed that listener after the first click. Toggle a few task buttons, click Abort task listeners, then try the task buttons again: the listeners are gone as a group.
The AbortController pattern is cleaner than keeping an array of functions to remove one by one. It is especially useful when a component, modal, or temporary panel creates several listeners and needs one cleanup switch when it disappears.
passive is different: it is not cleanup. It is a promise about browser defaults. If a listener is passive, do not call event.preventDefault() inside it. Some browsers will ignore that call and warn in the console. Cancellation itself belongs in the next lessons, especially links, event flow, and form submission.
The everyday event checklist
When you add browser behavior, ask four questions:
- Which element should listen?
- Which event name describes the user action?
- Which named function should run, especially if I may remove it later?
- Does the listener need lifetime options like
onceorsignal, or apassivepromise?
That checklist keeps interactive DOM code small. Find the element, register a listener, read the event object, then use the DOM tools from Section 14 to update text, classes, attributes, or layout.
Next, you will learn why a click that starts on a child can be heard by an ancestor, and how that event flow lets one listener manage many elements without wiring every button by hand.
Checkpoint
Answer all three to mark this lesson complete