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