DOM Manipulation with JavaScript
The Document Object Model (DOM) is a programming interface for web documents. It represents the page so that programs can change the document structure, style, and content. JavaScript is the primary language used to manipulate the DOM, allowing you to create dynamic and interactive web pages.
What is the DOM?
The DOM represents an HTML document as a tree of nodes. Each node represents a part of the document (elements, attributes, text, etc.). JavaScript can access and manipulate these nodes to change the content, structure, and style of a web page.
<!-- HTML Document -->
<html>
<head>
<title>My Page</title>
</head>
<body>
<h1 id="heading">Hello World</h1>
<p class="content">This is a paragraph.</p>
</body>
</html>
The above HTML document would be represented as a DOM tree like this:
document └── html ├── head │ └── title │ └── "My Page" (text node) └── body ├── h1 (id="heading") │ └── "Hello World" (text node) └── p (class="content") └── "This is a paragraph." (text node)
Selecting DOM Elements
Before you can manipulate elements, you need to select them. JavaScript provides several methods to select DOM elements:
Selecting Elements by ID
// Select an element with the ID "heading"
const headingElement = document.getElementById("heading");
console.log(headingElement); // Returns the h1 element
Selecting Elements by Class Name
// Select all elements with the class "content"
const contentElements = document.getElementsByClassName("content");
console.log(contentElements); // HTMLCollection [p.content]
console.log(contentElements[0]); // Returns the first element with class "content"
Selecting Elements by Tag Name
// Select all paragraph elements
const paragraphs = document.getElementsByTagName("p");
console.log(paragraphs); // HTMLCollection of paragraph elements
Using CSS Selectors (Modern Methods)
// Select the first element that matches a CSS selector
const headingBySelector = document.querySelector("#heading");
console.log(headingBySelector); // Returns the element with id="heading"
// Select all elements that match a CSS selector
const paragraphsBySelector = document.querySelectorAll("p.content");
console.log(paragraphsBySelector); // NodeList of matching elements
// More complex selectors
const nestedItems = document.querySelectorAll("ul > li");
const activeLinks = document.querySelectorAll("a.active");
const oddRows = document.querySelectorAll("tr:nth-child(odd)");
Tip: querySelector
and querySelectorAll
are more powerful and flexible than the older methods because they accept any valid CSS selector. They are the preferred methods for modern web development.
Manipulating DOM Elements
Changing Text Content
// Using textContent (recommended for most cases)
const heading = document.getElementById("heading");
heading.textContent = "Updated Heading";
// Using innerText (similar to textContent but respects CSS styling)
heading.innerText = "Another Update";
// Using innerHTML (can include HTML tags, but be careful with security)
heading.innerHTML = "New <em>Emphasized</em> Heading";
Warning: Be cautious when using innerHTML
with user-provided content, as it can lead to cross-site scripting (XSS) vulnerabilities. Use textContent
for plain text updates.
Changing Attributes
// Get an attribute
const link = document.querySelector("a");
const href = link.getAttribute("href");
console.log(href); // e.g., "https://example.com"
// Set an attribute
link.setAttribute("href", "https://newurl.com");
link.setAttribute("target", "_blank");
// Check if an attribute exists
const hasTitle = link.hasAttribute("title");
console.log(hasTitle); // true or false
// Remove an attribute
link.removeAttribute("target");
// Direct property access (for common attributes)
link.href = "https://anotherurl.com";
link.id = "main-link";
Manipulating CSS Classes
const element = document.querySelector(".my-element");
// Add a class
element.classList.add("highlight");
// Remove a class
element.classList.remove("old-class");
// Toggle a class (add if not present, remove if present)
element.classList.toggle("active");
// Replace one class with another
element.classList.replace("old-class", "new-class");
// Check if an element has a specific class
const hasClass = element.classList.contains("highlight");
console.log(hasClass); // true or false
Changing Inline Styles
const element = document.querySelector(".my-element");
// Set individual style properties
element.style.color = "blue";
element.style.backgroundColor = "yellow";
element.style.padding = "10px";
element.style.borderRadius = "5px";
// Note: CSS properties with hyphens are written in camelCase
// e.g., "background-color" becomes "backgroundColor"
// Getting computed styles (actual styles after CSS is applied)
const computedStyle = window.getComputedStyle(element);
console.log(computedStyle.color); // rgb(0, 0, 255)
console.log(computedStyle.fontSize); // 16px
Creating and Modifying Elements
Creating New Elements
// Create a new element
const newParagraph = document.createElement("p");
// Add content to the new element
newParagraph.textContent = "This is a dynamically created paragraph.";
// Add attributes
newParagraph.id = "dynamic-para";
newParagraph.classList.add("highlight");
// Add styles
newParagraph.style.color = "green";
newParagraph.style.fontWeight = "bold";
Adding Elements to the DOM
// Get the parent element where we want to add the new element
const container = document.querySelector(".container");
// Append the new element as the last child
container.appendChild(newParagraph);
// Insert at a specific position
const referenceElement = document.querySelector(".reference");
container.insertBefore(newParagraph, referenceElement);
// Modern methods (better browser support)
container.append(newParagraph); // Add as last child
container.prepend(newParagraph); // Add as first child
referenceElement.before(newParagraph); // Add before reference
referenceElement.after(newParagraph); // Add after reference
Removing Elements
// Remove an element (older method)
const elementToRemove = document.getElementById("old-element");
elementToRemove.parentNode.removeChild(elementToRemove);
// Modern method
elementToRemove.remove();
Cloning Elements
// Clone an element
const original = document.querySelector(".original");
const clone = original.cloneNode(); // Shallow clone (just the element)
const deepClone = original.cloneNode(true); // Deep clone (element and all its children)
// Add the clone to the DOM
document.querySelector(".container").appendChild(deepClone);
Traversing the DOM
Parent, Children, and Siblings
const element = document.querySelector(".my-element");
// Parent node
const parent = element.parentNode; // or element.parentElement
// Children
const children = element.children; // HTMLCollection of child elements
const firstChild = element.firstElementChild;
const lastChild = element.lastElementChild;
// Siblings
const nextSibling = element.nextElementSibling;
const previousSibling = element.previousElementSibling;
// All nodes (including text nodes and comments)
const childNodes = element.childNodes;
const firstNode = element.firstChild;
const lastNode = element.lastChild;
Interactive Example: DOM Manipulation
Live DOM Manipulation
Original Heading
This is a paragraph that can be modified.
- Item 1
- Item 2
Working with Events (Preview)
DOM manipulation is often combined with event handling to create interactive web pages. Here's a brief preview of event handling (covered in more detail in the Events topic):
// Add a click event listener
const button = document.getElementById("my-button");
button.addEventListener("click", function(event) {
console.log("Button clicked!");
console.log(event); // Event object with details about the event
// Manipulate the DOM in response to the event
document.getElementById("result").textContent = "Button was clicked!";
});
Best Practices for DOM Manipulation
- Minimize DOM Manipulations: DOM operations can be expensive. Batch your changes when possible.
- Use Document Fragments: When adding multiple elements, use document fragments to minimize reflows.
- Cache DOM References: Store references to elements you use repeatedly rather than querying the DOM multiple times.
- Prefer Modern Methods: Use
querySelector
/querySelectorAll
and modern manipulation methods for cleaner code. - Be Cautious with innerHTML: Avoid using
innerHTML
with user input to prevent XSS attacks. - Use CSS Classes for Styling: Instead of manipulating inline styles directly, toggle CSS classes when possible.
- Consider Performance: Be mindful of performance, especially when working with large DOM trees or frequent updates.
// Example of using document fragments
const fragment = document.createDocumentFragment();
const list = document.getElementById("my-list");
// Add 100 items to the fragment (not directly to the DOM)
for (let i = 0; i < 100; i++) {
const li = document.createElement("li");
li.textContent = `Item ${i + 1}`;
fragment.appendChild(li);
}
// Add the fragment to the DOM (just one reflow)
list.appendChild(fragment);
Next Steps
Now that you understand DOM manipulation, you can explore:
- Event handling in JavaScript
- Creating interactive forms
- Building dynamic user interfaces
- Working with AJAX and fetching data
- Using JavaScript frameworks that abstract DOM manipulation (React, Vue, Angular)