DOM Manipulation with JavaScript - Complete Guide
Master DOM manipulation in JavaScript. Learn to select elements, modify content, handle events, and create dynamic web pages with practical examples.
DOM Manipulation with JavaScript
The Document Object Model (DOM) is a programming interface for HTML documents. It represents the page structure as a tree of objects that JavaScript can manipulate to create dynamic, interactive web pages.
What is the DOM? #
The DOM represents your HTML document as a tree structure where each HTML element is a node. JavaScript can:
- Find and select elements
- Modify element content and attributes
- Add or remove elements
- Respond to user events
- Change CSS styles
Selecting Elements #
querySelector and querySelectorAll #
Modern JavaScript uses querySelector()
for single elements and querySelectorAll()
for multiple elements:
// Select single element (returns first match)
const header = document.querySelector('h1');
const firstButton = document.querySelector('.btn');
const emailInput = document.querySelector('#email');
// Select multiple elements (returns NodeList)
const allButtons = document.querySelectorAll('.btn');
const allParagraphs = document.querySelectorAll('p');
const allInputs = document.querySelectorAll('input[type="text"]');
Other Selection Methods #
// By ID (returns single element)
const element = document.getElementById('myId');
// By class name (returns HTMLCollection)
const elements = document.getElementsByClassName('myClass');
// By tag name (returns HTMLCollection)
const paragraphs = document.getElementsByTagName('p');
Modifying Element Content #
textContent vs innerHTML #
const element = document.querySelector('#myElement');
// textContent - sets/gets text only (safe from XSS)
element.textContent = 'Hello World';
console.log(element.textContent); // "Hello World"
// innerHTML - sets/gets HTML content (can be dangerous)
element.innerHTML = '<strong>Hello World</strong>';
console.log(element.innerHTML); // "<strong>Hello World</strong>"
// innerText - similar to textContent but considers styling
element.innerText = 'Visible text only';
Modifying Attributes #
const image = document.querySelector('img');
// Get attributes
const src = image.getAttribute('src');
const alt = image.getAttribute('alt');
// Set attributes
image.setAttribute('src', 'new-image.jpg');
image.setAttribute('alt', 'New description');
// Remove attributes
image.removeAttribute('title');
// Direct property access (for common attributes)
image.src = 'another-image.jpg';
image.alt = 'Another description';
Working with CSS Classes #
const element = document.querySelector('.my-element');
// Add classes
element.classList.add('active');
element.classList.add('highlighted', 'important');
// Remove classes
element.classList.remove('inactive');
// Toggle classes
element.classList.toggle('visible'); // adds if not present, removes if present
// Check if class exists
if (element.classList.contains('active')) {
console.log('Element is active');
}
// Replace class
element.classList.replace('old-class', 'new-class');
Modifying Styles #
const element = document.querySelector('.box');
// Set individual styles
element.style.color = 'red';
element.style.backgroundColor = 'blue';
element.style.fontSize = '18px';
// Set multiple styles using cssText
element.style.cssText = 'color: red; background-color: blue; font-size: 18px;';
// Get computed styles
const computedStyles = window.getComputedStyle(element);
const color = computedStyles.color;
const fontSize = computedStyles.fontSize;
Creating and Adding Elements #
// Create new element
const newDiv = document.createElement('div');
newDiv.textContent = 'Hello World';
newDiv.className = 'my-new-div';
// Create text node
const textNode = document.createTextNode('This is text');
// Add element to DOM
const container = document.querySelector('#container');
container.appendChild(newDiv);
// Insert before specific element
const referenceElement = document.querySelector('.reference');
container.insertBefore(newDiv, referenceElement);
// Insert using insertAdjacentHTML
container.insertAdjacentHTML('beforeend', '<p>New paragraph</p>');
Removing Elements #
const element = document.querySelector('.to-remove');
// Modern way (recommended)
element.remove();
// Older way
element.parentNode.removeChild(element);
// Remove all children
const container = document.querySelector('#container');
container.innerHTML = ''; // Quick but loses event listeners
// Better way to remove all children
while (container.firstChild) {
container.removeChild(container.firstChild);
}
Event Handling #
Adding Event Listeners #
const button = document.querySelector('#myButton');
// Add event listener
button.addEventListener('click', function(event) {
console.log('Button clicked!');
console.log('Event type:', event.type);
console.log('Target element:', event.target);
});
// Using arrow function
button.addEventListener('click', (event) => {
event.preventDefault(); // Prevent default behavior
console.log('Arrow function handler');
});
// Multiple event types
button.addEventListener('mouseenter', handleMouseEnter);
button.addEventListener('mouseleave', handleMouseLeave);
function handleMouseEnter(event) {
event.target.style.backgroundColor = 'lightblue';
}
function handleMouseLeave(event) {
event.target.style.backgroundColor = '';
}
Event Object Properties #
document.addEventListener('click', function(event) {
console.log('Event type:', event.type);
console.log('Target element:', event.target);
console.log('Current target:', event.currentTarget);
console.log('Mouse coordinates:', event.clientX, event.clientY);
console.log('Key pressed:', event.key); // for keyboard events
});
Event Delegation #
Instead of adding event listeners to many elements, add one listener to a parent:
// Instead of this (inefficient for many items):
document.querySelectorAll('.item').forEach(item => {
item.addEventListener('click', handleItemClick);
});
// Do this (event delegation):
document.querySelector('#itemContainer').addEventListener('click', function(event) {
if (event.target.classList.contains('item')) {
handleItemClick(event);
}
});
function handleItemClick(event) {
console.log('Item clicked:', event.target.textContent);
}
Form Handling #
const form = document.querySelector('#myForm');
const nameInput = document.querySelector('#name');
const emailInput = document.querySelector('#email');
// Handle form submission
form.addEventListener('submit', function(event) {
event.preventDefault(); // Prevent page reload
// Get form data
const formData = new FormData(form);
const name = formData.get('name');
const email = formData.get('email');
// Or get values directly
const nameValue = nameInput.value;
const emailValue = emailInput.value;
console.log('Form submitted:', { name, email });
});
// Handle input changes
nameInput.addEventListener('input', function(event) {
console.log('Name changed to:', event.target.value);
});
Practical Example: Todo List #
Best Practices #
1. Cache DOM References #
// Bad: Querying DOM repeatedly
function updateUI() {
document.querySelector('#counter').textContent = count;
document.querySelector('#counter').style.color = 'red';
document.querySelector('#counter').classList.add('updated');
}
// Good: Cache the reference
const counterElement = document.querySelector('#counter');
function updateUI() {
counterElement.textContent = count;
counterElement.style.color = 'red';
counterElement.classList.add('updated');
}
2. Use Event Delegation #
// Good for dynamic content
document.querySelector('#todoList').addEventListener('click', function(event) {
if (event.target.classList.contains('delete-btn')) {
deleteTodo(event.target.dataset.todoId);
} else if (event.target.classList.contains('complete-btn')) {
completeTodo(event.target.dataset.todoId);
}
});
3. Avoid innerHTML for User Input #
// Dangerous (XSS vulnerability)
element.innerHTML = userInput;
// Safe
element.textContent = userInput;
Common Patterns #
Toggle Visibility #
function toggleElement(selector) {
const element = document.querySelector(selector);
element.style.display = element.style.display === 'none' ? 'block' : 'none';
}
// Or using classes
function toggleElementClass(selector) {
document.querySelector(selector).classList.toggle('hidden');
}
Smooth Scrolling #
function scrollToElement(selector) {
const element = document.querySelector(selector);
element.scrollIntoView({ behavior: 'smooth' });
}
Summary #
DOM manipulation is essential for creating interactive web applications. Key concepts include:
- Selecting elements with
querySelector()
andquerySelectorAll()
- Modifying content with
textContent
andinnerHTML
- Managing classes with
classList
methods - Handling events with
addEventListener()
- Creating/removing elements dynamically
- Event delegation for efficient event handling
Practice these techniques to build dynamic, interactive web pages!
Next Steps #
Related Tutorials
Asynchronous JavaScript - Promises, Async/Await, and Fetch
Master asynchronous programming in JavaScript with promises, async/await, and the Fetch API. Learn to handle API calls, timers, and concurrent operations.
Best Way to Learn JavaScript: Common Questions Answered
Find answers to frequently asked questions about the best way to learn JavaScript, including timelines, resources, and effective study methods.
Last updated: Jan 11, 2025
ES6+ Features Every JavaScript Developer Should Know
Master modern JavaScript with ES6+ features including arrow functions, destructuring, modules, async/await, and more essential syntax improvements.
How to Turn On JavaScript: Complete Guide for All Browsers
Learn how to turn on JavaScript in Chrome, Firefox, Safari, and Edge with step-by-step instructions and troubleshooting tips.
Last updated: Jul 11, 2025