05 - DOM Manipulation
What is the DOM?
The Document Object Model (DOM) is a tree representation of your HTML that JavaScript can interact with. It lets you read and modify web page content, structure, and styling.
<!DOCTYPE html>
<html>
<body>
<h1 id="title">Hello World</h1>
<p class="text">This is a paragraph</p>
<script>
// JavaScript can access and modify these elements
const title = document.getElementById("title");
console.log(title.textContent); // "Hello World"
</script>
</body>
</html>Selecting Elements
// By ID — returns single element
const title = document.getElementById("title");
// By class name — returns HTMLCollection (array-like)
const paragraphs = document.getElementsByClassName("text");
// By tag name — returns HTMLCollection
const allDivs = document.getElementsByTagName("div");
// Query selector — returns first match (CSS selector syntax)
const first = document.querySelector(".text");
const byId = document.querySelector("#title");
const complex = document.querySelector("div.container > p");
// Query selector all — returns NodeList (array-like)
const all = document.querySelectorAll(".text");
// Modern approach — use querySelector/querySelectorAllModifying Content
const element = document.querySelector("#title");
// Text content — safe, doesn't parse HTML
element.textContent = "New Title";
// Inner HTML — can include HTML tags (be careful with user input)
element.innerHTML = "<strong>Bold Title</strong>";
// Inner text — respects CSS visibility
element.innerText = "Visible Text";
// Example
const container = document.querySelector(".container");
container.innerHTML = `
<h2>Dynamic Content</h2>
<p>Created with JavaScript</p>
`;Modifying Styles
const box = document.querySelector(".box");
// Direct style modification
box.style.color = "red";
box.style.backgroundColor = "blue";
box.style.fontSize = "20px";
// Multiple styles
Object.assign(box.style, {
color: "white",
backgroundColor: "black",
padding: "20px",
borderRadius: "5px"
});
// Better approach — use CSS classes
box.classList.add("highlighted");
box.classList.remove("hidden");
box.classList.toggle("active"); // add if not present, remove if present
// Check if class exists
if (box.classList.contains("active")) {
console.log("Box is active");
}Modifying Attributes
const link = document.querySelector("a");
// Get attribute
const href = link.getAttribute("href");
// Set attribute
link.setAttribute("href", "https://example.com");
link.setAttribute("target", "_blank");
// Remove attribute
link.removeAttribute("target");
// Check if attribute exists
if (link.hasAttribute("href")) {
console.log("Link has href");
}
// Direct property access (for common attributes)
link.href = "https://example.com";
link.className = "active";
link.id = "main-link";
// Data attributes
const element = document.querySelector(".card");
element.dataset.userId = "123"; // <div data-user-id="123">
console.log(element.dataset.userId); // "123"Creating Elements
// Create element
const div = document.createElement("div");
div.textContent = "New element";
div.className = "box";
// Add to page
document.body.appendChild(div);
// Insert at specific position
const container = document.querySelector(".container");
container.appendChild(div); // add to end
container.prepend(div); // add to beginning
// Insert before/after another element
const reference = document.querySelector(".reference");
reference.before(div); // insert before
reference.after(div); // insert after
// More complex example
const card = document.createElement("div");
card.className = "card";
card.innerHTML = `
<h3>Card Title</h3>
<p>Card description</p>
<button>Click Me</button>
`;
document.body.appendChild(card);Removing Elements
const element = document.querySelector(".remove-me");
// Modern way
element.remove();
// Old way (still works)
element.parentNode.removeChild(element);
// Remove all children
const container = document.querySelector(".container");
container.innerHTML = ""; // quick but loses event listeners
// Better — remove one by one
while (container.firstChild) {
container.firstChild.remove();
}Event Listeners
Make your page interactive by responding to user actions:
const button = document.querySelector("button");
// Add click event
button.addEventListener("click", () => {
console.log("Button clicked!");
});
// Event with parameter
button.addEventListener("click", (event) => {
console.log(event.target); // the button element
console.log(event.type); // "click"
});
// Multiple event types
const input = document.querySelector("input");
input.addEventListener("focus", () => {
console.log("Input focused");
});
input.addEventListener("blur", () => {
console.log("Input lost focus");
});
input.addEventListener("input", (e) => {
console.log("Current value:", e.target.value);
});
// Form submission
const form = document.querySelector("form");
form.addEventListener("submit", (e) => {
e.preventDefault(); // stop page reload
console.log("Form submitted");
});Common Events
// Mouse events
element.addEventListener("click", handler);
element.addEventListener("dblclick", handler);
element.addEventListener("mouseenter", handler);
element.addEventListener("mouseleave", handler);
element.addEventListener("mousemove", handler);
// Keyboard events
document.addEventListener("keydown", (e) => {
console.log(`Key pressed: ${e.key}`);
});
document.addEventListener("keyup", handler);
// Form events
input.addEventListener("input", handler); // any change
input.addEventListener("change", handler); // after blur
input.addEventListener("focus", handler);
input.addEventListener("blur", handler);
// Window events
window.addEventListener("load", handler); // page fully loaded
window.addEventListener("resize", handler); // window resized
window.addEventListener("scroll", handler); // page scrolledEvent Delegation
Handle events on dynamically added elements:
// ❌ Won't work for dynamically added buttons
const buttons = document.querySelectorAll("button");
buttons.forEach((btn) => {
btn.addEventListener("click", () => console.log("Clicked"));
});
// ✅ Works for all buttons, even future ones
document.body.addEventListener("click", (e) => {
if (e.target.matches("button")) {
console.log("Button clicked:", e.target.textContent);
}
});
// Real-world example — todo list
const list = document.querySelector("#todo-list");
list.addEventListener("click", (e) => {
if (e.target.matches(".delete-btn")) {
e.target.closest("li").remove();
}
if (e.target.matches(".todo-item")) {
e.target.classList.toggle("completed");
}
});Traversing the DOM
Navigate between elements:
const element = document.querySelector(".current");
// Parent
const parent = element.parentElement;
// Children
const children = element.children; // HTMLCollection
const firstChild = element.firstElementChild;
const lastChild = element.lastElementChild;
// Siblings
const next = element.nextElementSibling;
const prev = element.previousElementSibling;
// Find closest ancestor matching selector
const container = element.closest(".container");
// Example — find parent card
const button = document.querySelector(".delete-btn");
const card = button.closest(".card");
card.remove();Practical Example — Counter
<!DOCTYPE html>
<html>
<head>
<style>
.counter {
text-align: center;
margin: 50px;
}
.count {
font-size: 48px;
margin: 20px;
}
button {
padding: 10px 20px;
margin: 5px;
font-size: 16px;
cursor: pointer;
}
</style>
</head>
<body>
<div class="counter">
<h1>Counter App</h1>
<div class="count">0</div>
<button id="decrement">-</button>
<button id="reset">Reset</button>
<button id="increment">+</button>
</div>
<script>
let count = 0;
const display = document.querySelector(".count");
document.getElementById("increment").addEventListener("click", () => {
count++;
display.textContent = count;
});
document.getElementById("decrement").addEventListener("click", () => {
count--;
display.textContent = count;
});
document.getElementById("reset").addEventListener("click", () => {
count = 0;
display.textContent = count;
});
</script>
</body>
</html>Key Takeaways
- Use
querySelectorandquerySelectorAllfor selecting elements - Modify content with
textContent(safe) orinnerHTML(for HTML) - Add/remove CSS classes with
classListinstead of inline styles - Create elements with
createElementand add them withappendChild - Use
addEventListenerto respond to user interactions - Event delegation handles events on dynamically added elements
- Always
preventDefault()on form submit to stop page reload - Traverse the DOM with
parentElement,children,closest(), etc.