The Document Object Model (DOM) is a programming interface for HTML and XML documents. It represents the page as a tree of nodes that JavaScript can read and modify.

The DOM Tree

Every HTML element becomes a node in the tree:

  <html>
  <body>
    <h1 id="title">Hello</h1>
    <p class="text">World</p>
  </body>
</html>
  
  • document is the root
  • htmlbodyh1, p are child nodes

Selecting Elements

  // By ID (returns one element)
let title = document.getElementById('title');

// By class (returns HTMLCollection)
let paragraphs = document.getElementsByClassName('text');

// By tag name
let allP = document.getElementsByTagName('p');

// Modern selectors (recommended)
let el = document.querySelector('#title');       // first match
let all = document.querySelectorAll('.text');    // NodeList of all matches
  

Reading and Modifying Content

  let heading = document.querySelector('#title');

// Text content (safe, no HTML parsing)
heading.textContent = 'Hello, JavaScript!';

// Inner HTML (parses HTML tags)
heading.innerHTML = '<em>Hello</em>, JavaScript!';

// Attributes
heading.setAttribute('class', 'highlight');
heading.classList.add('active');
heading.classList.remove('active');
heading.classList.toggle('active');
  

Creating and Removing Elements

  // Create
let newP = document.createElement('p');
newP.textContent = 'A new paragraph';
newP.classList.add('text');

// Append
document.body.appendChild(newP);

// Insert before another element
let container = document.querySelector('#container');
container.insertBefore(newP, container.firstChild);

// Remove
newP.remove(); // modern
// container.removeChild(newP); // older syntax
  

Traversing the DOM

  let node = document.querySelector('p');

node.parentElement;    // parent element
node.children;         // child elements
node.nextElementSibling;
node.previousElementSibling;
node.firstElementChild;
node.lastElementChild;
  

Complete Example

  <!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>DOM Example</title>
    <style>
        .done { text-decoration: line-through; color: gray; }
    </style>
</head>
<body>
    <h1 id="title">Todo List</h1>
    <ul id="list"></ul>
    <input id="input" type="text" placeholder="New task">
    <button id="addBtn">Add</button>

    <script>
        const list = document.querySelector('#list');
        const input = document.querySelector('#input');
        const addBtn = document.querySelector('#addBtn');

        function addTask(text) {
            const li = document.createElement('li');
            li.textContent = text;
            li.addEventListener('click', () => li.classList.toggle('done'));
            list.appendChild(li);
        }

        addBtn.addEventListener('click', () => {
            if (input.value.trim()) {
                addTask(input.value.trim());
                input.value = '';
            }
        });
    </script>
</body>
</html>
  

Best Practices

  • Prefer querySelector / querySelectorAll over older APIs
  • Use textContent instead of innerHTML when inserting user data (prevents XSS)
  • Cache DOM references in variables instead of querying repeatedly inside loops
  • Wait for DOMContentLoaded before manipulating elements when scripts are in <head>