18 / 20 · Day 6
Day 6 · Concept 18

The browser DOM

In the browser, JS has access to the document tree, the network (fetch), input events, and storage. Modern apps use frameworks — but knowing vanilla DOM debugs every framework problem.


1 · Selecting elements

js select.js
// Single element
const btn = document.querySelector("#submit");
const main = document.querySelector("main.content");

// All matching
const links = document.querySelectorAll("a[href^='/']");
for (const a of links) console.log(a.href);

// By id (faster, when you have it)
const header = document.getElementById("header");

querySelector takes any CSS selector. querySelectorAll returns a NodeList — iterable, not quite an array (use Array.from to convert).

2 · Mutating the DOM

js mutate.js
// Create elements
const el = document.createElement("div");
el.className = "card";
el.textContent = "Hello";

// Insert
document.body.appendChild(el);
parent.insertBefore(newEl, refEl);
parent.removeChild(el);

// Attributes
el.setAttribute("data-id", "42");
el.getAttribute("data-id");
el.dataset.id;        // also "42" — friendlier

// Inline style
el.style.backgroundColor = "tomato";

// Class list
el.classList.add("active");
el.classList.toggle("open");

3 · Events

js events.js
btn.addEventListener("click", event => {
    console.log("clicked", event.target);
    event.preventDefault();        // don't navigate / submit
    event.stopPropagation();       // don't bubble
});

// Delegation — attach once, handle for many children
list.addEventListener("click", event => {
    const item = event.target.closest("li");
    if (item) handleClick(item.dataset.id);
});

// Remove
btn.removeEventListener("click", handler);

// Once-only
btn.addEventListener("click", handler, { once: true });

4 · Fetch

js fetch.js
// GET
const res = await fetch("/api/users");
if (!res.ok) throw new Error(`HTTP ${res.status}`);
const users = await res.json();

// POST
const res2 = await fetch("/api/users", {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify({ name: "Alice" }),
});

// AbortController for cancellation
const ctrl = new AbortController();
setTimeout(() => ctrl.abort(), 5000);
const res3 = await fetch("/api/slow", { signal: ctrl.signal });

5 · Storage — localStorage, sessionStorage, cookies

js storage.js
// localStorage — strings only, persists across sessions
localStorage.setItem("user", JSON.stringify({ id: 1 }));
const user = JSON.parse(localStorage.getItem("user") || "null");
localStorage.removeItem("user");
localStorage.clear();

// sessionStorage — same API, cleared on tab close
sessionStorage.setItem("token", "tmp");

// Cookies — automatic on requests; document.cookie is rough

6 · Common mistakes

  • Querying before DOMContentLoaded. Defer scripts or wait for the event.
  • Forgetting preventDefault on form submit. The page refreshes and you lose state.
  • Adding listeners without removing. Memory leaks build up across SPA route changes.
  • Using innerHTML with user data. XSS risk. Use textContent for plain text.

7 · When it clicks

  • You debug React/Vue components by checking the DOM directly.
  • Event delegation is reflex for dynamic lists.
  • You reach for fetch + async/await without thinking.
Found this useful?