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?

Published Updated