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?