intermediate
Step 10 of 20
DOM Manipulation
JavaScript Programming
DOM Manipulation
The Document Object Model (DOM) is a programming interface that represents an HTML document as a tree of objects. Each HTML element becomes a node in this tree, and JavaScript can access and manipulate every part of it — changing text, styles, attributes, and structure dynamically. DOM manipulation is how you make web pages interactive: responding to user actions, updating content without page reloads, showing and hiding elements, and building dynamic user interfaces. This is the core of front-end JavaScript development.
Selecting Elements
// Modern selectors (preferred)
const header = document.querySelector("h1"); // First h1
const allButtons = document.querySelectorAll(".btn"); // All elements with class "btn"
const nav = document.querySelector("#main-nav"); // Element with id "main-nav"
const activeLink = document.querySelector("nav a.active"); // CSS selector
// Legacy selectors (still used)
const byId = document.getElementById("header");
const byClass = document.getElementsByClassName("item"); // Live HTMLCollection
const byTag = document.getElementsByTagName("p"); // Live HTMLCollection
// querySelectorAll returns a static NodeList
allButtons.forEach(btn => {
console.log(btn.textContent);
});
// Convert NodeList/HTMLCollection to Array for full array methods
const btnArray = [...document.querySelectorAll(".btn")];
const filtered = btnArray.filter(btn => btn.dataset.type === "primary");
Modifying Content and Attributes
const heading = document.querySelector("h1");
// Text content
heading.textContent = "New Heading"; // Sets text (safe — escapes HTML)
heading.innerHTML = "New Heading"; // Sets HTML (careful — XSS risk)
// Attributes
const link = document.querySelector("a");
link.setAttribute("href", "https://example.com");
link.getAttribute("href");
link.removeAttribute("target");
link.hasAttribute("rel");
// Shorthand for common attributes
const img = document.querySelector("img");
img.src = "photo.jpg";
img.alt = "A photo";
img.id = "hero-image";
// Data attributes
const card = document.querySelector(".card");
card.dataset.userId = "123"; // Sets data-user-id="123"
console.log(card.dataset.userId); // Reads data-user-id
// Classes
const element = document.querySelector(".box");
element.classList.add("active", "highlight");
element.classList.remove("hidden");
element.classList.toggle("dark-mode");
element.classList.contains("active"); // true
element.classList.replace("old", "new");
// Styles
element.style.backgroundColor = "#f0f0f0";
element.style.padding = "20px";
element.style.display = "none";
// Better: toggle classes instead of inline styles
element.classList.add("hidden"); // .hidden { display: none; }
Creating and Inserting Elements
// Create elements
const newDiv = document.createElement("div");
newDiv.className = "card";
newDiv.innerHTML = `
New Card
Card content here
`;
// Insert into the DOM
const container = document.querySelector(".container");
container.appendChild(newDiv); // Add at end
container.prepend(newDiv); // Add at beginning
container.insertBefore(newDiv, referenceNode); // Insert before specific element
// Modern insertion methods
container.append(newDiv, "text node"); // Append multiple nodes/text
container.before(newDiv); // Insert before container
container.after(newDiv); // Insert after container
// insertAdjacentHTML — powerful insertion without destroying existing content
container.insertAdjacentHTML("beforeend", `
Dynamic Item
Created with insertAdjacentHTML
`);
// Positions: "beforebegin", "afterbegin", "beforeend", "afterend"
// Remove elements
const oldElement = document.querySelector(".old");
oldElement.remove();
// or: oldElement.parentNode.removeChild(oldElement);
// Clone elements
const clone = newDiv.cloneNode(true); // true = deep clone (with children)
container.appendChild(clone);
Building a Dynamic List
// Practical example: render a list of items
function renderUserList(users) {
const list = document.querySelector("#user-list");
list.innerHTML = ""; // Clear existing content
if (users.length === 0) {
list.innerHTML = 'No users found.
';
return;
}
const fragment = document.createDocumentFragment(); // Performance optimization
users.forEach(user => {
const li = document.createElement("li");
li.className = "user-item";
li.dataset.id = user.id;
li.innerHTML = `
${user.name}
${user.email}
`;
fragment.appendChild(li);
});
list.appendChild(fragment); // Single DOM update (better performance)
}
renderUserList([
{ id: 1, name: "Alice", email: "alice@example.com" },
{ id: 2, name: "Bob", email: "bob@example.com" }
]);
Pro tip: Minimize direct DOM manipulation for better performance. Batch your changes usingDocumentFragment, useclassListinstead of inline styles, and prefertextContentoverinnerHTMLwhen you do not need to parse HTML (it is faster and avoids XSS vulnerabilities).
Key Takeaways
- Use
querySelector()andquerySelectorAll()with CSS selectors to find elements — they are the modern standard. - Modify content with
textContent(safe) orinnerHTML(parses HTML — watch for XSS). - Use
classList.add()/remove()/toggle()for CSS classes — avoid manipulatingclassNamedirectly. - Create elements with
createElement()and insert withappend(),prepend(), orinsertAdjacentHTML(). - Use
DocumentFragmentfor batch DOM insertions to minimize reflows and improve performance.