The DOM — Tree, Selectors & Traversal

প্রতিটি web page একটি গাছ — JS সেই গাছ পরিবর্তন করে

~40 min Intermediate 16 practice problems Live runner

1. The Page Is a Tree

The browser parses HTML into a Document Object Model — a live tree of nodes that JavaScript can read, change, add to, or delete from. document is the root, window is the global.

document html head body h1 p Figure 25.1 — every HTML element is a tree node; JS API is the same regardless of depth.

2. Selectors

// Single element — first match
const el = document.querySelector("#title");
const btn = document.querySelector(".btn-primary");

// All matches — static NodeList
const items = document.querySelectorAll("li.todo");
items.forEach(li => console.log(li.textContent));

// Legacy
document.getElementById("title");
document.getElementsByClassName("btn"); // live HTMLCollection
document.getElementsByTagName("p");
querySelector CSS selector ব্যবহার করে — সবচেয়ে শক্তিশালী এবং পরিচিত। querySelectorAll static — পরে DOM বদলালেও list পরিবর্তন হবে না। getElementsByClassName live — DOM বদলে সাথে সাথে list update হয়।

3. Traversal

// element-only navigation (skips text nodes)
el.parentElement
el.children                  // HTMLCollection
el.firstElementChild
el.lastElementChild
el.previousElementSibling
el.nextElementSibling

// Node-level (includes text nodes — usually you don't want these)
el.parentNode
el.childNodes
el.firstChild

// Climb the tree until a selector matches
el.closest(".card")

4. Reading & Writing Content

el.textContent = "হ্যালো";       // safe text
el.innerHTML   = "<b>Hi</b>";   // parses HTML — XSS risk if untrusted
el.innerText                       // visible text only (slower)
el.value                           // for inputs

el.setAttribute("data-id", 42);
el.getAttribute("data-id");
el.dataset.id      // = "42"  — preferred for data-* attrs
el.classList.add("active");
el.classList.remove("hidden");
el.classList.toggle("dark");
el.style.color = "red";
XSS rule Never put untrusted strings into innerHTML. Use textContent for text and createElement + appendChild for structure.

5. Creating & Inserting Elements

const li = document.createElement("li");
li.textContent = "নতুন item";
li.classList.add("todo");

document.querySelector("ul").appendChild(li);

// Modern alternative — accept strings or nodes
parent.append(li, "extra text", anotherNode);
parent.prepend(li);
sibling.before(li);
sibling.after(li);

// Remove
li.remove();

6. Sandbox-Safe DOM Mock

Our in-page runner has no real document. Below is a tiny mock so you can practice the API patterns inside the runner.

mock.js
class MockEl {
    constructor(tag) {
        this.tag = tag;
        this.children = [];
        this.textContent = "";
        this.classList = new Set();
    }
    append(child) { this.children.push(child); }
}

const ul = new MockEl("ul");
["কেনাকাটা", "পড়াশোনা", "ব্যায়াম"].forEach(t => {
    const li = new MockEl("li");
    li.textContent = t;
    li.classList.add("todo");
    ul.append(li);
});

console.log(`<ul> has ${ul.children.length} children:`);
ul.children.forEach(li => console.log("·", li.textContent));

7. Glossary (শব্দকোষ)

TermMeaningবাংলায়
DOMDocument Object Model — live tree representing the page.Page-এর live tree representation।
documentThe root of the DOM tree.DOM tree-এর root।
windowThe browser's global object.Browser-এর global object।
querySelectorReturns the first element matching a CSS selector.CSS selector-এর প্রথম মিল-যাওয়া element।
NodeListStatic list returned by querySelectorAll.querySelectorAll-এর static list।
HTMLCollectionLive list returned by getElementsByClassName/TagName.getElementsByClassName-এর live list।
textContentPlain-text content — XSS-safe.Plain text — XSS-নিরাপদ।
innerHTMLHTML markup — XSS-risky with user input.HTML markup — user input দিলে XSS ঝুঁকি।
closestClimbs the tree until a selector matches.Selector মিল না হওয়া পর্যন্ত উপরে যায়।
datasetReads/writes data-* attributes as object properties.data-* attribute-কে object-এর মতো access।
সংক্ষেপে: Page একটি tree; querySelector দিয়ে খুঁজুন এবং textContent / classList / dataset দিয়ে নিরাপদে edit করুন। User-এর data কখনোই innerHTML-এ বসাবেন না — XSS-এর সরাসরি দরজা। DOM মূলত imperative API; React-এর মতো framework-এ এটিই declarative হয়ে যায়।

8. Practice Problems

  1. Write a CSS selector to grab all links inside a nav with class "main".
    ✨ Show Answer

    document.querySelectorAll("nav.main a")

  2. Set a heading's text to "হ্যালো!".
    ✨ Show Answer
    document.querySelector("h1").textContent = "হ্যালো!";
  3. Toggle a "dark" class on the body when a button is clicked.
    ✨ Show Answer
    btn.addEventListener("click",
        () => document.body.classList.toggle("dark"));
  4. Build a runnable mock that lists 3 todo items as objects.
    ✨ Show Answer
    a4.js
    const todos = [
        { text: "কেনাকাটা", done: false },
        { text: "পড়াশোনা", done: true },
        { text: "ব্যায়াম",    done: false },
    ];
    todos.forEach(t =>
        console.log(`[${t.done ? "x" : " "}] ${t.text}`));
  5. What's the difference between querySelectorAll (static) and getElementsByClassName (live)?
    ✨ Show Answer

    Answer: querySelectorAll takes a snapshot — adding/removing elements after the call doesn't change the NodeList. getElementsByClassName returns a live HTMLCollection that automatically reflects DOM changes. Live collections are surprising in loops where you mutate the DOM.

  6. Use closest to find the nearest .card ancestor.
    ✨ Show Answer
    e.target.closest(".card").remove();
  7. Show why innerHTML = userInput is a security risk.
    ✨ Show Answer

    If userInput is <img src=x onerror="steal()">, the browser will parse and execute it. Always use textContent or DOM-built nodes for user data.

  8. Build an HTML table from a JS array (sketch).
    ✨ Show Answer
    const tbody = document.querySelector("tbody");
    data.forEach(row => {
        const tr = document.createElement("tr");
        Object.values(row).forEach(v => {
            const td = document.createElement("td");
            td.textContent = v;
            tr.appendChild(td);
        });
        tbody.appendChild(tr);
    });
  9. Use dataset to read a custom data-id attribute.
    ✨ Show Answer
    // <li data-id="42"> → li.dataset.id === "42"
    const id = el.dataset.id;
  10. Demonstrate that adding to a live HTMLCollection inside a for loop misbehaves.
    ✨ Show Answer

    If list = document.getElementsByClassName("x") and you add a new element with class "x" inside a loop, list.length grows during iteration — the loop never ends. Snapshot first: [...list].forEach(...).

  11. Sketch a function that toggles dark mode based on system preference.
    ✨ Show Answer
    const m = matchMedia("(prefers-color-scheme: dark)");
    const sync = () => document.body.classList.toggle("dark", m.matches);
    sync();
    m.addEventListener("change", sync);
  12. Replace an element entirely with a new one (sketch).
    ✨ Show Answer
    old.replaceWith(newEl);
    // or
    parent.replaceChild(newEl, old);
  13. Show why setting style.color = "red" overrides CSS — and how to avoid it.
    ✨ Show Answer

    Inline styles win over external stylesheets (except for !important). Prefer toggling classes — it keeps style logic in CSS where it belongs.

  14. Build a runnable "render todo list" simulation that converts an array to console.log lines.
    ✨ Show Answer
    a14.js
    const render = todos => todos.map(t =>
        `<li class="${t.done ? "done" : ""}">${t.text}</li>`);
    console.log(render([{ text: "কেনাকাটা", done: false }, { text: "পড়া", done: true }]));
  15. Why is the DOM API often called "imperative"?
    ✨ Show Answer

    Answer: You tell the browser the exact steps — "create this node, set this property, append it here." Frameworks like React invert that to declarative: you describe the UI as a function of state and the framework figures out the minimal DOM mutations.

  16. Show how to clear all children of a list.
    ✨ Show Answer
    // Fast and clean
    ul.replaceChildren();
    // or
    ul.innerHTML = "";

Summary — Module 25

The DOM is the live tree representing your page. Use querySelector/querySelectorAll to find nodes, textContent to read/write text safely, classList for styling, createElement + append to build new content, and closest for upward search. Avoid innerHTML with untrusted strings.

প্রতিটি page একটি tree। querySelector দিয়ে খুঁজুন; textContent safe; innerHTML XSS-প্রবণ। class toggle দিয়ে style বদলান।

Next Module → Events — bubbling, delegation এবং custom events।