Skip to content

Lesson 9 of 9 · 20m

JavaScript in the Browser: DOM, Events, and fetch

The platform APIs underneath every framework — how the DOM actually works, why events bubble, and fetch patterns that don't leak race conditions.

Frameworks come and go; the DOM API has been stable for twenty-five years. Understanding what React does for you starts with knowing what it does instead of — and sometimes the platform is genuinely all you need.

The DOM is a tree you query, then mutate

const el = document.querySelector(".toast");
el.textContent = "Saved";
el.classList.add("visible");

Three habits that prevent real bugs:

  • textContent, never innerHTML, for user data — innerHTML with user input is the XSS in most audit reports.
  • addEventListener, not onclick attributes — multiple listeners, removal, no global pollution.
  • Delegate events on stable ancestors instead of attaching to elements that get re-rendered: one listener on the list handles clicks on rows that don't exist yet.

Events bubble — use it

A click on a button fires on the button, then its parent, then document. event.target is what was clicked; event.currentTarget is what you attached to. That distinction is the whole trick behind event delegation.

fetch: the failure modes are the API

const ctrl = new AbortController();
const res = await fetch("/api/data", { signal: ctrl.signal });
if (!res.ok) throw new Error(`HTTP ${res.status}`);
const data = await res.json();

Two traps everyone hits once: fetch does not reject on 404 or 500 — you must check res.ok yourself — and a fetch that outlives its screen needs AbortController or it writes state into a component the user already left.

Try it yourself

const res = await fetch("https://api.github.com/zen");
console.log(res.ok, res.status, await res.text());

// Abort a request you no longer need:
const ctrl = new AbortController();
fetch("https://api.github.com/zen", { signal: ctrl.signal });
ctrl.abort(); // cancelled — the promise rejects with AbortError

Rules of thumb

  • Reach for the platform first: dialog.showModal(), details/summary, IntersectionObserver cover most "I need a library" moments.
  • Every event listener and timer is a leak candidate — pair addEventListener with cleanup, setInterval with clearInterval.
  • If your vanilla code is getting tangled, that is the signal for a framework — not the starting point.