DOM Manipulation
Selecting and updating elements
The DOM (Document Object Model)
The DOM is a tree-like representation of your HTML that JavaScript can read and modify. Every HTML element is a node in this tree.
Selecting Elements
// Select single element
const heading = document.querySelector('h1');
const button = document.querySelector('#submit-btn');
const firstCard = document.querySelector('.card');
// Select multiple elements (returns NodeList)
const allCards = document.querySelectorAll('.card');
const allLinks = document.querySelectorAll('a');
// NodeList can be iterated
allCards.forEach(card => {
console.log(card.textContent);
});
// Old methods (still work, but querySelector is preferred)
const byId = document.getElementById('my-id');
const byClass = document.getElementsByClassName('my-class');
const byTag = document.getElementsByTagName('p');
Modifying Content
const element = document.querySelector('#content');
// Change text content (safe, no HTML parsing)
element.textContent = "Hello, World!";
// Change HTML content (be careful with user input!)
element.innerHTML = 'Hello, World!';
// Change specific attribute
const link = document.querySelector('a');
link.href = 'https://example.com';
link.title = 'Visit Example';
// Using setAttribute
link.setAttribute('target', '_blank');
link.setAttribute('rel', 'noopener');
Modifying Styles
const box = document.querySelector('.box');
// Direct style modification (inline styles)
box.style.backgroundColor = 'blue';
box.style.width = '200px';
box.style.padding = '20px';
// Add/remove classes (preferred method)
box.classList.add('active');
box.classList.remove('hidden');
box.classList.toggle('dark-mode');
// Check if class exists
if (box.classList.contains('active')) {
console.log('Box is active');
}
// Multiple classes
box.classList.add('large', 'rounded', 'shadow');
Creating & Adding Elements
// Create new element
const div = document.createElement('div');
div.textContent = 'Hello';
div.className = 'card';
div.id = 'my-card';
// Add to DOM
const container = document.querySelector('#container');
container.appendChild(div); // Add to end
container.prepend(div); // Add to beginning
// Insert adjacent
const reference = document.querySelector('.reference');
reference.insertAdjacentElement('beforebegin', div); // Before element
reference.insertAdjacentElement('afterbegin', div); // First child
reference.insertAdjacentElement('beforeend', div); // Last child
reference.insertAdjacentElement('afterend', div); // After element
// Insert HTML string
element.insertAdjacentHTML('beforeend', 'New paragraph
');
Removing Elements
const element = document.querySelector('.to-remove');
// Modern way
element.remove();
// Old way (still works)
element.parentNode.removeChild(element);
// Remove all children
const container = document.querySelector('#container');
container.innerHTML = ''; // Quick but not ideal
// Better way to remove all children
while (container.firstChild) {
container.removeChild(container.firstChild);
}
Traversing the DOM
const element = document.querySelector('.item');
// Parents
element.parentElement; // Direct parent
element.closest('.container'); // Nearest ancestor matching selector
// Children
element.children; // All child elements (HTMLCollection)
element.firstElementChild; // First child
element.lastElementChild; // Last child
// Siblings
element.nextElementSibling; // Next sibling
element.previousElementSibling; // Previous sibling
Getting & Setting Attributes
const img = document.querySelector('img');
// Get attribute
const src = img.getAttribute('src');
const alt = img.getAttribute('alt');
// Set attribute
img.setAttribute('src', 'new-image.jpg');
img.setAttribute('alt', 'New image');
// Remove attribute
img.removeAttribute('title');
// Check if attribute exists
if (img.hasAttribute('data-id')) {
console.log('Has data-id');
}
// Data attributes
img.dataset.userId = '123'; // Sets data-user-id="123"
console.log(img.dataset.userId); // "123"
Practical Examples
// Example 1: Toggle visibility
const button = document.querySelector('#toggle-btn');
const content = document.querySelector('#content');
button.addEventListener('click', () => {
content.classList.toggle('hidden');
});
// Example 2: Dynamic list
const list = document.querySelector('#todo-list');
const input = document.querySelector('#todo-input');
const addBtn = document.querySelector('#add-btn');
addBtn.addEventListener('click', () => {
const text = input.value.trim();
if (!text) return;
const li = document.createElement('li');
li.textContent = text;
li.className = 'todo-item';
list.appendChild(li);
input.value = ''; // Clear input
});
// Example 3: Form validation
const form = document.querySelector('#signup-form');
const emailInput = document.querySelector('#email');
const error = document.querySelector('#error');
form.addEventListener('submit', (e) => {
e.preventDefault();
const email = emailInput.value;
if (!email.includes('@')) {
error.textContent = 'Invalid email';
error.classList.remove('hidden');
emailInput.classList.add('error');
} else {
error.classList.add('hidden');
emailInput.classList.remove('error');
// Submit form...
}
});
🎯 Performance Tips
- • Cache DOM queries (don't query the same element repeatedly)
- • Use
documentFragmentfor multiple insertions - • Batch DOM changes together (causes fewer reflows)
- • Use event delegation for many similar elements
⚠️ Common Pitfalls
- • Setting
innerHTMLwith user input (XSS vulnerability!) - • Not checking if element exists before manipulating
- • Querying inside loops (cache outside instead)
- • Forgetting that
querySelectorAllreturns a NodeList, not Array
✓ Best Practices
- • Use
querySelector/querySelectorAllfor selecting - • Prefer
textContentoverinnerHTMLwhen no HTML needed - • Use
classListmethods instead of className manipulation - • Cache DOM references in variables
- • For complex UIs, consider using a framework (React, Vue, etc.)