Topics in this subject
JavaScript 3 min read Updated 4 Aug 2026

Part 17 — The DOM

Selecting, Creating, inserting, removing, Traversal & attributes, Events, bubbling, capturing, delegation 🎯, Forms & storage

The Document Object Model is a live tree of objects representing the page. JS reads and changes it to make pages interactive. (These APIs are browser-only, not part of ECMAScript.)

Selecting#

document.getElementById("id");
document.querySelector(".card");        // first match (CSS selector) 🟢
document.querySelectorAll("li");        // static NodeList of all matches
element.closest(".panel");              // nearest ancestor matching selector
element.matches(".active");             // boolean

⚠️ querySelectorAll returns a static NodeList; getElementsByClassName/getElementsByTagName return live collections that update as the DOM changes.

Creating, inserting, removing#

const el = document.createElement("div");
el.textContent = "safe text";           // 🟢 no HTML parsing (XSS-safe)
el.classList.add("card");
el.dataset.id = "42";                    // data-id="42"
parent.append(el, "text", otherNode);    // modern, multiple nodes
parent.prepend(el);
el.before(node); el.after(node); el.replaceWith(node);
el.remove();                             // delete self

⚠️ innerHTML parses HTML — never set it from user input (XSS). Prefer textContent. If you must build HTML, sanitize (DOMPurify) or use element.setHTML() where available.

Traversal & attributes#

el.children; el.parentElement; el.nextElementSibling;
el.getAttribute("href"); el.setAttribute("aria-hidden", "true");
el.hidden = true; el.style.color = "red";
el.classList.toggle("open", isOpen);

Events, bubbling, capturing, delegation 🎯#

ELI12. When you click a button inside a list, the click "bubbles" up: button → list → body → document. You can catch it anywhere along the way. Event delegation means putting one listener on the parent instead of many on each child.

graph TD
    D[document] -->|capture ↓| B[body]
    B --> UL[ul]
    UL --> LI[li clicked]
    LI -->|bubble ↑| UL
    UL --> B2[body]
    B2 --> D2[document]
el.addEventListener("click", handler, { capture:false, once:true, passive:true });
el.removeEventListener("click", handler);   // must be the SAME function reference

// event delegation — one listener handles many children
list.addEventListener("click", (e) => {
  const item = e.target.closest("li");
  if (!item) return;
  console.log("clicked", item.dataset.id);
});

// prevent default & stop propagation
form.addEventListener("submit", (e) => {
  e.preventDefault();        // stop page reload
  e.stopPropagation();       // stop bubbling to ancestors
});
  • Capturing phase goes top→target; bubbling goes target→top (default addEventListener listens in bubble phase). Pass {capture:true} for the capture phase.
  • passive:true promises you won't call preventDefault — lets the browser scroll smoothly.
  • Delegation benefits: fewer listeners, works for dynamically added elements.

Forms & storage#

const data = new FormData(formEl);
data.get("email");
Object.fromEntries(data);          // → plain object

localStorage.setItem("k", JSON.stringify(v));  // persists, ~5MB, strings only, sync
JSON.parse(localStorage.getItem("k"));
sessionStorage;                    // cleared when tab closes
document.cookie;                   // small, sent with requests

Observers & misc#

new MutationObserver(cb).observe(node, { childList:true, subtree:true });
new IntersectionObserver(cb).observe(el);   // visibility (lazy-load, infinite scroll)
new ResizeObserver(cb).observe(el);         // element size changes
history.pushState({}, "", "/new-url");      // SPA routing
navigator.clipboard.writeText("copied");    // async clipboard

Best practices: batch DOM writes (reads then writes) to avoid layout thrashing; use documentFragment or requestAnimationFrame for bulk updates; prefer textContent over innerHTML; remove listeners you no longer need.

Interview questions (Part 17):

  1. Explain event bubbling vs capturing and event delegation's benefits.
  2. innerHTML vs textContent — security and performance.
  3. Live vs static NodeLists.
  4. Why must removeEventListener receive the same function reference?