xSKILLby Infirals
Register

JavaScript for Beginners

0 of 24 notes read 0%

Reading progress is saved to your INFIRALS account. Sign in to keep this note marked as read.

Events, listeners and forms

DOM and events16 min readLesson 2 of 4

2.1 What an event is

An event is a signal that something happened: a click, a key press, a form submission, a timer finishing or an image loading. The browser creates an event object, then calls the listeners registered for that event type on the target and its ancestors.

A listener is a function registered with addEventListener. It receives the event object as its first argument. The same function can be registered once per event type and element; registering it again does not create a duplicate, because the browser compares the function and the options.

Events are asynchronous in the sense that they happen after the current script finishes. A listener cannot interrupt a running loop, and the page stays responsive between events.

2.2 Adding and removing listeners

element.addEventListener("click", handler) registers a listener. The third argument can be options: once removes the listener after the first call, and capture changes the phase in which it runs. A matching removeEventListener call needs the same function reference and the same capture setting.

Removing a listener matters in longer-lived pages. A component that adds a listener to the window on every open and never removes it leaves old handlers running after the component is gone. A named handler held in a variable makes the removal possible; an inline arrow cannot be removed later.

javascript
const button = document.createElement("button");
const output = document.createElement("p");
button.textContent = "Add";
document.body.append(button, output);

let count = 0;
button.addEventListener("click", () => {
  count += 1;
  output.textContent = `Clicked ${count} times`;
});

button.click();
button.click();

console.log(count);
console.log(output.textContent);

Output

2
Clicked 2 times

2.3 The event object

The handler receives an object with useful fields. event.type is the event name. event.target is the element that received the event, and event.currentTarget is the element whose listener is running. The difference matters when an event bubbles.

event.preventDefault() stops the browser's default action for that event, such as following a link or submitting a form. The listener must be registered for a cancelable event, and calling preventDefault on a passive listener has no effect. For form validation, the default action is exactly what you want to stop.

event.stopPropagation() stops the event from reaching later listeners in the bubble order. Use it rarely. Delegation and layered behaviour usually work better when events keep travelling and each listener decides what to do.

javascript
const inner = document.createElement("span");
const outer = document.createElement("div");
outer.append(inner);
document.body.append(outer);

outer.addEventListener("click", (event) => {
  console.log(event.target.tagName);
  console.log(event.currentTarget.tagName);
});

inner.click();

Output

SPAN
DIV

2.4 Bubbling and delegation

A click on an inner element bubbles up through its ancestors, calling listeners on each. That lets one listener on a list handle clicks for every item inside it. The listener reads event.target, finds the nearest item with closest, and updates data by id.

Delegation is useful when the list changes. New items added later are handled without registering new listeners, and removing an item removes its listener with it. The delegated listener also keeps the code in one place, which is easier to test and reason about.

event.target.closest("li") walks up from the clicked node to the nearest list item. If the click lands on the list padding, closest returns null, and the handler should return early. A guard at the top of a delegated handler prevents accidental matches.

2.5 Forms and validation

A form submit fires when the user presses a submit button or hits Enter in a field. The browser attempts to send the data and reload the page unless the handler calls preventDefault. A single-page form usually stops the default, validates the fields, and renders a message or sends a fetch request.

Validation runs in two layers. HTML attributes such as required, minlength and type="email" give instant browser checks. JavaScript adds business rules the attributes cannot express, such as matching two passwords or checking a list of allowed values. Never rely on the browser alone for security; server checks are mandatory.

Read field values from the input element, not from the DOM text around it. Trim strings before checking, and show the message next to the field rather than in an alert. A form that explains the problem in place is easier to fix than one that clears the page.

javascript
const form = document.createElement("form");
const input = document.createElement("input");
const message = document.createElement("p");
form.append(input, message);
document.body.append(form);

form.addEventListener("submit", (event) => {
  event.preventDefault();
  const value = input.value.trim();

  if (value.length < 3) {
    message.textContent = "Enter at least 3 characters";
    return;
  }

  message.textContent = `Saved: ${value}`;
});

input.value = "Aarav";
form.dispatchEvent(new Event("submit", { cancelable: true }));
console.log(message.textContent);

input.value = "Al";
form.dispatchEvent(new Event("submit", { cancelable: true }));
console.log(message.textContent);

Output

Saved: Aarav
Enter at least 3 characters

2.6 Event phases

An event travels through three phases. The capture phase runs from the window down to the target, the target phase runs listeners on the target, and the bubble phase runs from the target back up to the window. Most listeners use the bubble phase, which is the default.

A listener registered with { capture: true } runs during the capture phase. Capturing is useful for intercepting an event before it reaches a component, such as closing an open menu when a click lands anywhere outside it. The same listener options must match when removing the listener.

Some events do not bubble, such as focus and blur in older browser behaviour, and mouseenter does not bubble at all. Use the bubbling alternatives focusin and mouseover when delegation is needed, or attach the listener directly to each element.

2.7 Keyboard accessibility

Clicks are not the only input. A real button handles Enter and Space automatically, which is a reason to build controls from button elements. For custom widgets, handle keydown and check event.key for Enter, Space, Escape and the arrow keys.

Focus order follows the document order unless tabindex changes it. Keep tabindex at 0 for elements that should be reachable and avoid positive values, which reorder the page for everyone. After an action that changes the page, move focus to the part the user needs next.

A form that submits on Enter is expected behaviour; a custom div that submits on click is not. The browser's built-in controls carry keyboard and screen-reader support that hand-rolled elements must rebuild, and rebuilding it correctly takes more code than using the right element.

2.8 Common mistakes

  • Forgetting preventDefault on a form submit and losing the page state on reload.
  • Registering a listener in a loop and leaking one handler per item.
  • Using event.target when the listener sits on an ancestor and the clicked node is a child.
  • Removing a listener with a different function reference than the one registered.
  • Relying on HTML validation for rules that need a server check.
  • Calling stopPropagation by default instead of letting events bubble.

Exam

Event questions usually ask what the handler receives or what the page shows after a sequence. Track the phase: target, then ancestors, then the default action. If preventDefault is missing, the browser's default behaviour is part of the answer.

  • Add a click listener to a button and log the event type.
  • Build a nested element and log target and currentTarget.
  • Stop a form submit and validate one field.
  • Rewrite two item listeners as one delegated listener.