Learning Objectives
- Select elements with querySelector and getElementById
- Create and append new elements
- Modify element content and attributes
- Remove and replace elements
- Apply DOM manipulation best practices
What is the DOM?
The Document Object Model (DOM) is a programming interface for HTML documents. It represents the page as a tree of objects that JavaScript can manipulate to create dynamic, interactive web pages.
Selecting Elements
// By ID - fastest method
const header = document.getElementById('header');
// By CSS selector - most flexible (first match)
const button = document.querySelector('.btn-primary');
const firstItem = document.querySelector('#list > li:first-child');
// By CSS selector - all matches
const items = document.querySelectorAll('.list-item');
items.forEach(item => console.log(item));
// By class name - returns HTMLCollection
const cards = document.getElementsByClassName('card');
// By tag name
const paragraphs = document.getElementsByTagName('p');
// Modern approach - use querySelector/querySelectorAll
const nav = document.querySelector('nav.navbar');
const links = document.querySelectorAll('a[href^="http"]');
Creating Elements
// Create element
const div = document.createElement('div');
// Set attributes
div.className = 'container';
div.id = 'main-container';
div.setAttribute('data-id', '123');
// Set content
div.textContent = 'Hello World'; // Text only
div.innerHTML = 'Hello World
'; // HTML
// Create with content
const paragraph = document.createElement('p');
paragraph.textContent = 'This is a paragraph';
// Append to DOM
document.body.appendChild(div);
div.appendChild(paragraph);
// Insert at specific position
const parent = document.querySelector('#parent');
const firstChild = parent.firstChild;
parent.insertBefore(div, firstChild);
Modifying Elements
const element = document.querySelector('#myElement');
// Change content
element.textContent = 'New text content';
element.innerHTML = 'New HTML content';
// Change attributes
element.setAttribute('data-id', '123');
element.getAttribute('data-id'); // '123'
element.removeAttribute('data-id');
// Direct property access
element.id = 'newId';
element.className = 'new-class another-class';
element.href = 'https://example.com';
// Change styles
element.style.color = 'blue';
element.style.backgroundColor = '#f0f0f0';
element.style.fontSize = '16px';
// Better - use CSS classes
element.classList.add('active');
element.classList.remove('hidden');
element.classList.toggle('visible');
element.classList.contains('active'); // true/false
// Replace class
element.classList.replace('old-class', 'new-class');
Removing Elements
// Remove element (modern)
const element = document.querySelector('#myElement');
element.remove();
// Remove child (older method)
const parent = document.querySelector('#parent');
const child = document.querySelector('#child');
parent.removeChild(child);
// Clear all children
parent.innerHTML = '';
// Better performance - remove children one by one
while (parent.firstChild) {
parent.removeChild(parent.firstChild);
}
// Replace element
const newElement = document.createElement('div');
newElement.textContent = 'New content';
element.replaceWith(newElement);
Real-World Examples
Todo List
function createTodoItem(text) {
const li = document.createElement('li');
li.className = 'todo-item';
const checkbox = document.createElement('input');
checkbox.type = 'checkbox';
checkbox.addEventListener('change', () => {
span.classList.toggle('completed');
});
const span = document.createElement('span');
span.textContent = text;
const deleteBtn = document.createElement('button');
deleteBtn.textContent = 'Delete';
deleteBtn.className = 'btn-delete';
deleteBtn.addEventListener('click', () => {
li.remove();
});
li.appendChild(checkbox);
li.appendChild(span);
li.appendChild(deleteBtn);
return li;
}
function addTodo(text) {
const todoList = document.querySelector('#todoList');
const item = createTodoItem(text);
todoList.appendChild(item);
}
// Usage
addTodo('Learn DOM manipulation');
addTodo('Build a project');
Dynamic Table
function createTable(data) {
const table = document.createElement('table');
table.className = 'data-table';
// Create header
const thead = document.createElement('thead');
const headerRow = document.createElement('tr');
Object.keys(data[0]).forEach(key => {
const th = document.createElement('th');
th.textContent = key;
headerRow.appendChild(th);
});
thead.appendChild(headerRow);
table.appendChild(thead);
// Create body
const tbody = document.createElement('tbody');
data.forEach(row => {
const tr = document.createElement('tr');
Object.values(row).forEach(value => {
const td = document.createElement('td');
td.textContent = value;
tr.appendChild(td);
});
tbody.appendChild(tr);
});
table.appendChild(tbody);
return table;
}
// Usage
const users = [
{ name: 'John', age: 30, email: 'john@example.com' },
{ name: 'Jane', age: 25, email: 'jane@example.com' }
];
const table = createTable(users);
document.body.appendChild(table);
Card Component
function createCard({ title, description, imageUrl, link }) {
const card = document.createElement('div');
card.className = 'card';
if (imageUrl) {
const img = document.createElement('img');
img.src = imageUrl;
img.alt = title;
card.appendChild(img);
}
const cardBody = document.createElement('div');
cardBody.className = 'card-body';
const h3 = document.createElement('h3');
h3.textContent = title;
const p = document.createElement('p');
p.textContent = description;
cardBody.appendChild(h3);
cardBody.appendChild(p);
if (link) {
const a = document.createElement('a');
a.href = link;
a.textContent = 'Read more';
a.className = 'btn';
cardBody.appendChild(a);
}
card.appendChild(cardBody);
return card;
}
// Usage
const cardData = {
title: 'DOM Manipulation',
description: 'Learn how to manipulate the DOM',
imageUrl: '/images/dom.jpg',
link: '/tutorials/dom'
};
const card = createCard(cardData);
document.querySelector('#cards-container').appendChild(card);
Best Practices
1. Cache DOM references
// Bad - queries DOM every time
for (let i = 0; i < 100; i++) {
document.querySelector('#list').appendChild(item);
}
// Good - cache reference
const list = document.querySelector('#list');
for (let i = 0; i < 100; i++) {
list.appendChild(item);
}
2. Use document fragments for batch updates
// Better performance
const fragment = document.createDocumentFragment();
for (let i = 0; i < 100; i++) {
const li = document.createElement('li');
li.textContent = `Item ${i}`;
fragment.appendChild(li);
}
list.appendChild(fragment); // Single reflow
3. Use textContent for text, innerHTML for HTML
// Safe - no XSS risk
element.textContent = userInput;
// Risky - potential XSS
element.innerHTML = userInput; // Only if sanitized!
4. Use classList instead of className
// Good
element.classList.add('active');
element.classList.remove('hidden');
element.classList.toggle('visible');
// Less flexible
element.className = 'active visible';
Key Takeaways
- DOM manipulation enables dynamic web pages
- Use
querySelectorfor modern, flexible element selection - Create elements with
createElement - Modify content with
textContent(safe) orinnerHTML(flexible) - Remove elements with
remove()orremoveChild() - Cache DOM references for better performance
- Use document fragments for batch updates
- Prefer
classListoverclassName - Always sanitize user input before using
innerHTML