⚡IntermediateBrowser JavaScript
DOM Manipulation
Select, create, modify, and remove HTML elements using the DOM API to build dynamic web pages.
Overview
The Document Object Model (DOM) is the browser's representation of an HTML page as a tree of objects. Every HTML tag becomes a node in this tree, and JavaScript can read and modify it in real time adding elements, changing text, updating styles, and removing nodes causing the page to update without a full reload.
The document object is your entry point. You select elements with methods like document.querySelector() (returns the first match) and document.querySelectorAll() (returns all matches as a NodeList). Once you have an element reference, you can read and set its textContent, innerHTML, className, style, and attributes.
DOM manipulation is the core of all dynamic web behavior: form validation, UI updates, rendering data from APIs, interactive components. Modern frameworks like React and Vue abstract over the raw DOM, but understanding the underlying API makes you a far stronger developer when debugging or working without a framework.
Key Points
- •document.querySelector(selector) returns the first matching element or null
- •document.querySelectorAll(selector) returns a NodeList of all matches
- •element.textContent sets/gets text safely (no HTML parsing); element.innerHTML parses HTML
- •element.setAttribute(name, value) and element.getAttribute(name) manage HTML attributes
- •element.classList.add(), .remove(), .toggle(), .contains() manage CSS classes
- •document.createElement(tag) creates a new element; parent.appendChild(el) inserts it
- •element.remove() removes an element from the DOM
- •element.style.property sets inline styles prefer toggling classes for maintainability
Examples
Selecting elements and changing content
// Assume this HTML: <h1 id="title">Hello</h1> <p class="intro">Welcome</p>
const title = document.querySelector("#title");
title.textContent = "Hello, World!";
const intro = document.querySelector(".intro");
intro.style.color = "blue";
intro.classList.add("highlight");
// Select all paragraphs
const paragraphs = document.querySelectorAll("p");
paragraphs.forEach(p => {
p.style.marginBottom = "10px";
});
console.log(title.textContent); // Hello, World!
console.log(paragraphs.length); // number of <p> elements on the pageRun this code in the browser console on any page to see it in action immediately.
Creating and inserting new elements
// Create a new list item and append it
const ul = document.querySelector("ul") || document.createElement("ul");
if (!ul.parentNode) document.body.appendChild(ul);
function addItem(text) {
const li = document.createElement("li");
li.textContent = text;
li.setAttribute("data-value", text.toLowerCase());
ul.appendChild(li);
return li;
}
addItem("Apples");
addItem("Bananas");
addItem("Cherries");
// Insert before a specific element
const firstItem = ul.firstElementChild;
const newFirst = document.createElement("li");
newFirst.textContent = "Avocados";
ul.insertBefore(newFirst, firstItem);
// Modern alternative: insertAdjacentElement
const li = document.createElement("li");
li.textContent = "Dates";
ul.lastElementChild.insertAdjacentElement("afterend", li);Modifying attributes and classes
// Assume: <img id="photo" src="old.jpg" alt="Photo">
const img = document.querySelector("#photo");
// Attributes
img.setAttribute("src", "new.jpg");
img.setAttribute("alt", "Updated photo");
console.log(img.getAttribute("src")); // new.jpg
// Classes
const btn = document.querySelector("#myBtn");
if (btn) {
btn.classList.add("active", "highlighted");
btn.classList.remove("disabled");
btn.classList.toggle("open");
console.log(btn.classList.contains("active")); // true
// Replace all classes
btn.className = "btn btn-primary";
}
// Dataset (data-* attributes)
const card = document.querySelector("[data-id]");
if (card) {
console.log(card.dataset.id);
card.dataset.status = "active"; // sets data-status="active"
}Common Mistakes
- Using innerHTML with user-provided content always sanitize or use textContent to avoid XSS attacks
- Calling querySelector before the DOM is ready wrap in DOMContentLoaded or place script at end of body
- Not checking if querySelector returned null before accessing properties causes TypeError
- Directly setting element.style instead of toggling classes inline styles are hard to override and maintain
Note
Prefer element.textContent over element.innerHTML for inserting text. innerHTML parses HTML and can execute scripts in certain contexts, making it a security risk when content comes from users or external sources.
Exercises
Write JavaScript code to solve each exercise. Run it and check your output.
Loading editor…
Completed: 0 / 5 exercises
Knowledge Check
Question 1 of 4