AV
HomeAboutProjectBlog

© 2026 Ave syah Shina. All rights reserved.

  1. Home
  2. Blog
  3. 11 — DOM APIs — Talking to the Page from JavaScript

11 — DOM APIs — Talking to the Page from JavaScript

August 13, 20266 min read
Download as Markdown

"The document object" was my DOM model, and it conflated the tree with the language that touches it. The idea that everything else hangs off: the DOM is a live tree of nodes the browser builds from the HTML, and JavaScript doesn't own it — it borrows a set of methods from the browser's host environment to query, change, and listen to that tree. [1]

The framing that finally landed is the host-environment split. The ECMAScript spec defines the core language (types, functions, closures). The DOM is specified separately — by the WHATWG/Web APIs — and provided by the browser. document, window, querySelector, addEventListener are not JavaScript. They're the browser's API surface, handed to the JS engine so my code can touch the page. That distinction explains why the same language in Node has no document — Node ships different host APIs.

HTML source <html> <body> <h1>Hi</h1> <button/> DOM tree (live, in memory) html body h1 "Hi" button JavaScript engine calls host API methods querySelector · listen · create

The tree, and how I find nodes

The browser parses HTML into a tree of nodes — element nodes, text nodes, comment nodes — rooted at document. Almost everything I do starts with finding the node I want [1]:

document.querySelector("#submit");        // first match by CSS selector
document.querySelectorAll(".item"); // all matches (a NodeList)
document.getElementById("submit"); // by id (legacy, fast)
element.closest(".card"); // nearest ancestor matching a selector

querySelector / querySelectorAll are the modern, universal tools — they take any CSS selector, so the same syntax I use for styling works for querying. The legacy methods (getElementById, getElementsByClassName) still exist and are slightly faster, but I rarely need the speed.

Changing the tree

Once I have a node, the API for reading and mutating it is large but the common moves are few [1]:

const btn = document.querySelector("#submit");
btn.textContent = "Save"; // change text
btn.setAttribute("disabled", ""); // change an attribute
btn.classList.add("loading"); // toggle a class
btn.style.color = "red"; // inline style (prefer classes)

// structure changes
const item = document.createElement("li"); // make a node
item.textContent = "New";
list.appendChild(item); // attach it
list.removeChild(oldItem); // remove one
oldItem.replaceWith(newItem); // swap one

Two things to keep straight. First, textContent vs innerHTML — textContent sets plain text safely; innerHTML parses HTML, which is both more powerful and an XSS vector if the content comes from user input. Second, prefer CSS classes over inline style writes — classes keep styling concerns in stylesheets, where they belong.

Listening to events

Interactivity is events. The pattern is addEventListener(event, callback) — register a function to run when something happens [1]:

btn.addEventListener("click", (event) => {
console.log(event.target); // the element that was clicked
doSave();
});

The callback receives an event object with details: event.target (the actual element clicked), event.currentTarget (the element the listener is attached to), event.preventDefault() (stop the default action), event.stopPropagation() (stop bubbling). Events bubble from the target up to the root, which is why event delegation works — one listener on a parent handles clicks on any of its children, useful when children are added dynamically.

Beyond the DOM: other Web APIs

The DOM is the headline, but browsers expose many more Web APIs that JavaScript can call [1]: Web Storage (localStorage, sessionStorage) for key-value persistence, Fetch for network requests, History for URL manipulation without reload, Geolocation, Canvas and WebGL for graphics, Web Workers for background threads. Each is a host API — not part of the language, lent by the browser, and absent in Node unless polyfilled.

How I use this

In a framework world (React, Vue, Svelte), I touch the DOM directly far less than I used to — the framework owns the tree and I declare state, not nodes. But the DOM APIs are still the substrate underneath, and they're essential for: reading a value the framework doesn't manage (a third-party widget, a measurement), integrating non-framework code, or building something without a framework. The rule I keep: reach for querySelector over legacy methods, prefer textContent and classes over innerHTML and inline styles, and use event delegation when children are dynamic. And remember that none of these methods are JavaScript — they're the browser's surface, and they won't exist in a Node script.

References

[1] Mozilla, "Document Object Model (DOM)," MDN Web Docs, 2024. [Online]. Available: https://developer.mozilla.org/en-US/docs/Web/API/Document_Object_Model

[2] Mozilla, "Introduction to events," MDN Web Docs, 2024. [Online]. Available: https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Building_blocks/Events

[3] Mozilla, "Element.querySelector()," MDN Web Docs, 2024. [Online]. Available: https://developer.mozilla.org/en-US/docs/Web/API/Document/querySelector

[4] Mozilla, "EventTarget.addEventListener()," MDN Web Docs, 2024. [Online]. Available: https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener

[5] Mozilla, "Web APIs — list of interfaces," MDN Web Docs, 2024. [Online]. Available: https://developer.mozilla.org/en-US/docs/Web/API

Knowledge check · Question 1 of 5

The DOM methods like querySelector and addEventListener are…

Comments

Leave a Comment

You must be signed in to comment

0 Comments

No comments yet. Be the first to comment!