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
// 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
// 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
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
// 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
// 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 rough6 · Common mistakes
- Querying before DOMContentLoaded. Defer scripts or wait for the event.
- Forgetting
preventDefaulton form submit. The page refreshes and you lose state. - Adding listeners without removing. Memory leaks build up across SPA route changes.
- Using
innerHTMLwith user data. XSS risk. UsetextContentfor 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/awaitwithout thinking.
Found this useful?