Beginner25 min read

DOM Manipulation

Learn to select, create, modify, and remove HTML elements using the Document Object Model.

What is the DOM?

The Document Object Model (DOM) is a programming interface that represents an HTML page as a tree of objects. When a browser loads an HTML document, it parses the markup and builds this tree structure in memory. Each HTML element, attribute, and piece of text becomes a node in the tree.

html
document
  └── html
      ├── head
      │   └── title
      │       └── "My Page"
      └── body
          ├── h1
          │   └── "Hello World"
          └── p
              └── "Welcome to my site."

JavaScript can read and modify every part of this tree — changing text, updating styles, adding new elements, removing existing ones, and responding to user interactions.

The entry point to the DOM is the document object. It represents the entire HTML page and provides methods to find and manipulate elements:

javascript
console.log(document.title);       // The page title
console.log(document.body);        // The <body> element
console.log(document.documentElement); // The <html> element

Understanding the DOM is essential for making web pages interactive. Every time you click a button, submit a form, or see content update dynamically on a website, the DOM is being manipulated by JavaScript.

Selecting Elements

Before you can modify an element, you need to select it. The DOM provides several methods for this:

getElementById() — selects a single element by its id attribute:

javascript
const header = document.getElementById('main-title');

Returns the element or null if no element with that id exists.

querySelector() — selects the first element that matches a CSS selector:

javascript
const firstButton = document.querySelector('button');
const submitBtn = document.querySelector('#submit-btn');
const highlight = document.querySelector('.highlight');
const navLink = document.querySelector('nav a.active');

This is the most versatile selection method because it accepts any valid CSS selector — IDs, classes, element types, attribute selectors, combinators, and more.

querySelectorAll() — selects all elements that match a CSS selector:

javascript
const allButtons = document.querySelectorAll('button');
const items = document.querySelectorAll('.list-item');

This returns a NodeList, which is similar to an array but is not a real array. You can loop over it with forEach or for...of, and access elements by index:

javascript
allButtons.forEach(btn => console.log(btn.textContent));
console.log(allButtons[0]); // first button
console.log(allButtons.length); // number of matches

There are also older methods like getElementsByClassName() and getElementsByTagName() that return live collections — they automatically update when the DOM changes. However, querySelector and querySelectorAll are generally preferred for their flexibility.

javascript
// These return live HTMLCollections:
const divs = document.getElementsByTagName('div');
const highlights = document.getElementsByClassName('highlight');

Modifying Elements

Once you have selected an element, you can modify its content, styles, and attributes.

Changing text content:

  • textContent — gets or sets the raw text. Safe — it does not parse HTML:

    javascript
    const heading = document.querySelector('h1');
    heading.textContent = 'New Heading';
  • innerHTML — gets or sets the HTML content, including tags:

    javascript
    const container = document.querySelector('#output');
    container.innerHTML = '<strong>Bold</strong> text';

    Security warning: Never use innerHTML with user-provided input. It can create Cross-Site Scripting (XSS) vulnerabilities because the browser will execute any <script> tags or event handlers in the string. Use textContent for user data.

Changing styles:

The style property gives you access to an element's inline styles. CSS property names are written in camelCase:

javascript
const box = document.querySelector('.box');
box.style.backgroundColor = 'blue';
box.style.fontSize = '20px';
box.style.border = '2px solid black';

Working with CSS classes is usually better than inline styles:

javascript
const element = document.querySelector('.card');
element.classList.add('active');       // Add a class
element.classList.remove('hidden');    // Remove a class
element.classList.toggle('expanded');  // Add if missing, remove if present
element.classList.contains('active');  // Check if class exists → true/false

Setting and getting attributes:

javascript
const link = document.querySelector('a');
link.setAttribute('href', 'https://example.com');
link.setAttribute('target', '_blank');

console.log(link.getAttribute('href')); // 'https://example.com'

Creating & Removing Elements

JavaScript can create entirely new elements and add them to the page, or remove existing ones.

Creating elements:

javascript
const newParagraph = document.createElement('p');
newParagraph.textContent = 'This paragraph was created by JavaScript.';
newParagraph.classList.add('dynamic');

At this point, the element exists in memory but is not yet on the page. You need to insert it into the DOM.

Adding elements to the page:

  • appendChild() — adds a child element at the end of a parent:

    javascript
    const container = document.getElementById('content');
    container.appendChild(newParagraph);
  • append() — like appendChild, but can also accept strings and multiple arguments:

    javascript
    container.append(newParagraph, 'Some text', anotherElement);
  • insertBefore() — inserts before a specific child element:

    javascript
    const reference = document.querySelector('#content p:first-child');
    container.insertBefore(newParagraph, reference);
  • insertAdjacentHTML() — inserts HTML at a specific position relative to the element:

    javascript
    container.insertAdjacentHTML('beforeend', '<p>New content</p>');
    // Positions: 'beforebegin', 'afterbegin', 'beforeend', 'afterend'

Removing elements:

javascript
const toRemove = document.querySelector('.old-content');
toRemove.remove(); // Removes the element from the DOM

Performance tip: When adding many elements at once, use a DocumentFragment to batch the changes. This avoids triggering a page re-render for each element:

javascript
const fragment = document.createDocumentFragment();
for (let i = 0; i < 100; i++) {
  const li = document.createElement('li');
  li.textContent = 'Item ' + i;
  fragment.appendChild(li);
}
document.getElementById('big-list').appendChild(fragment);
// Only one re-render instead of 100!

DOM Manipulation in Action

html
<div id="app">
  <h2>Dynamic Content</h2>
  <ul id="list"></ul>
</div>

<script>
  const items = ['Learn HTML', 'Learn CSS', 'Learn JavaScript'];
  const list = document.getElementById('list');

  // Create and append list items
  items.forEach(function(text) {
    const li = document.createElement('li');
    li.textContent = text;
    li.style.padding = '4px 0';
    list.appendChild(li);
  });

  // Add a new item
  const newItem = document.createElement('li');
  newItem.textContent = 'Build a project!';
  newItem.style.fontWeight = 'bold';
  newItem.style.color = 'green';
  list.appendChild(newItem);

  // Modify the heading
  const heading = document.querySelector('#app h2');
  heading.style.color = 'navy';
  heading.textContent = 'My Learning Path';
</script>

What method selects the first element matching a CSS selector?

Ready to practice?

Create your free account to access the interactive code editor, run challenges, and track your progress.