Skip to content

DOM Manipulation

The DOM (Document Object Model) is the version of your HTML that lives in memory, built by the browser.

JavaScript talks to this structure to:

  • Read content
  • Change elements
  • Respond to things the user does
graph TD A[HTML File] --> B[HTML Parsing] B --> C[DOM Tree] C --> D[CSS Parsing] D --> E[Render Tree] E --> F[Layout] F --> G[Paint]
  • DOM Tree -> this is the structure built from your HTML.
  • Render Tree -> this is the DOM combined together with the CSS.
  • Layout -> this step works out where everything should be positioned.
  • Paint -> this step actually draws the pixels onto the screen.

Dynamic UI

Lets you update content on the page without needing to reload it.

User Interaction

Lets you handle clicks, typing, and keyboard events.

Data Rendering

Lets you turn data from an API into something visible on the screen.

Real Apps

Used in things like forms, dashboards, modals (popups), and lists.

// Old ways
document.getElementById("id");
document.getElementsByClassName("class");
// Modern, flexible
document.querySelector(".card");
document.querySelectorAll(".btn");

getElementById

This is the fastest option, and it gives back a single element.

querySelector

This uses CSS selectors, so it is more flexible to use.

querySelectorAll

This gives back a NodeList (which is not exactly the same thing as an array).

element.textContent;
element.innerText;
element.innerHTML;
element.setAttribute("id", "main");
element.getAttribute("id");
element.classList.add("active");
element.classList.remove("hidden");
element.classList.toggle("open");
const div = document.createElement("div");
div.textContent = "Hello";
document.body.append(div);
graph LR A[Create Element] --> B[Set Content] B --> C[Append to DOM] C --> D[Rendered]
parent.append(child);
parent.prepend(child);
element.before(newNode);
element.after(newNode);
element.remove();
parent.removeChild(child);
oldEl.replaceWith(newEl);
graph TD A[Window] --> B[Document] B --> C[Parent] C --> D[Target] D --> E[Bubble Back]
  1. Capture phase (this goes from the top down to the target)
  2. Target phase (this is where the event actually happened)
  3. Bubble phase (this goes back up from the target to the top)

Instead of attaching a separate listener to every single element, you can attach just one listener to a parent element:

document.querySelector("#list").addEventListener("click", (e) => {
if (e.target.tagName === "LI") {
console.log("Item clicked");
}
});

Updating the DOM is not free, it actually costs some performance, so it is worth being careful with it.

for (let i = 0; i < 1000; i++) {
document.body.append(document.createElement("div"));
}

This is considered bad because it updates the actual page 1000 separate times, which is slow.

const fragment = document.createDocumentFragment();
for (let i = 0; i < 1000; i++) {
fragment.append(document.createElement("div"));
}
document.body.append(fragment);

This is better because all 1000 elements are first built up in memory, and the actual page is only updated once at the very end.

graph TD A[DOM Change] --> B{Layout Change?} B -->|Yes| C[Reflow] B -->|No| D[Repaint]
  • Reflow -> this means the layout has to be recalculated, which is expensive (slow).
  • Repaint -> this only updates how things look visually, without recalculating layout, so it is cheaper (faster).
const users = ["A", "B", "C"];
const ul = document.querySelector("#users");
ul.innerHTML = "";
users.forEach((user) => {
const li = document.createElement("li");
li.textContent = user;
ul.append(li);
});
element.innerHTML = userInput; // dangerous

This is risky because if userInput contains harmful code, it can actually run on your page. This kind of attack is called XSS (Cross-Site Scripting).

  1. Cache your DOM queries (save the result instead of searching for the same element again and again).
  2. Try to keep DOM updates to a minimum.
  3. Use event delegation where it makes sense.
  4. Prefer using textContent instead of innerHTML when you can, since it is safer.
  5. Use document fragments when you need to make a lot of updates at once.