Lesson 9 of 12

JavaScript DOM Manipulation

Everything so far has worked with data: numbers, arrays and objects. To make a page interactive, JavaScript needs a way to reach the HTML elements themselves. That bridge is the DOM, the Document Object Model. In this lesson on DOM manipulation you will learn to find elements, change them, and create new ones from your data.

What is the DOM?

When the browser loads an HTML file, it does not keep it as text. It builds a tree of objects in memory, one object (a node) for every element, piece of text and comment. The <html> element is at the top, <head> and <body> are its children, and so on down to each paragraph and link. That tree is the DOM.

JavaScript gets the whole tree through the global document object. Every element in it is an object with properties (like textContent and id) and methods (like remove()). When you change those objects, the browser updates the screen immediately. Your HTML file on disk is never changed – only the live page is.

Finding elements: the first step of DOM manipulation

MethodReturns
document.getElementById('menu')The one element with that id, or null
document.querySelector('.card h3')The first element matching a CSS selector, or null
document.querySelectorAll('.card')A NodeList of all matching elements (possibly empty)

querySelector() and querySelectorAll() accept any CSS selector, so everything you learned in CSS Selectors applies here: classes, ids, attributes, descendants and pseudo-classes. A NodeList is not a true array, but it supports forEach() and for…of; convert it with Array.from() if you need map() or filter(). You can also call these methods on an element to search only inside it.

Changing text: textContent vs innerHTML

element.textContent reads or replaces all the text inside an element. Whatever you assign is treated as plain text, so a < symbol appears as a < symbol. element.innerHTML, by contrast, parses the string as HTML and builds elements from it.

Watch out: Never put user-supplied text into innerHTML. If someone types <img src=x onerror="…"> into a form and you insert it with innerHTML, their code can run on your page. This is called cross-site scripting (XSS). Use textContent for text, and build elements with createElement() when you need structure.

Changing classes, styles and attributes

  • el.classList.add('active'), remove(), toggle() and contains() manage CSS classes. This is the preferred way to change appearance: keep the styles in CSS and let JavaScript switch classes.
  • el.style.backgroundColor = 'gold' sets an inline style. CSS property names become camelCase. Use it for values calculated in JavaScript, such as a progress bar width.
  • el.setAttribute('aria-expanded', 'true') and getAttribute() work with any attribute. Common ones also exist as properties: img.src, link.href, input.value, button.disabled.
  • el.dataset reads data-* attributes: <li data-price="250"> gives li.dataset.price === '250' (always a string).
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <title>DOM changes</title>
  <style>
    body { font-family: system-ui, sans-serif; padding: 16px; line-height: 1.5; }
    .budget { color: green; font-weight: bold; }
  </style>
</head>
<body>
  <h1 id="title">Today's menu</h1>
  <ul>
    <li class="dish" data-price="60">Masala dosa</li>
    <li class="dish" data-price="40">Idli vada</li>
    <li class="dish" data-price="90">Mini meals</li>
  </ul>
  <p class="note">Prices in rupees.</p>

  <script>
// Change text of one element
document.getElementById('title').textContent = "Today's menu (updated by JavaScript)";

// Work with every matching element
const dishes = document.querySelectorAll('.dish');
dishes.forEach((dish) => {
  const price = Number(dish.dataset.price);
  dish.textContent = `${dish.textContent} – Rs. ${price}`;
  if (price < 50) {
    dish.classList.add('budget');
  }
});

// Change a style and an attribute
const note = document.querySelector('.note');
note.style.fontStyle = 'italic';
note.setAttribute('title', 'Prices include GST');
  </script>
</body>
</html>

Creating and removing elements

To add new content, create an element with document.createElement(), fill it with textContent and attributes, then insert it with append() (at the end of a parent), prepend() (at the start), or before() / after() (next to an element). To delete an element, call el.remove(). Combined with an array of objects, this is how lists, tables and product cards are generated from data.

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <title>Create elements</title>
  <style>
    body { font-family: system-ui, sans-serif; padding: 16px; line-height: 1.5; }
    .near { color: #0a6; }
  </style>
</head>
<body>
  <h2>Weekend trips from Pondicherry</h2>
  <ul id="trips"></ul>
  <p id="count"></p>

  <script>
const trips = [
  { place: 'Auroville', km: 12 },
  { place: 'Mahabalipuram', km: 95 },
  { place: 'Chidambaram', km: 65 },
  { place: 'Gingee Fort', km: 70 }
];

const list = document.getElementById('trips');

for (const trip of trips) {
  const li = document.createElement('li');
  li.textContent = `${trip.place} (${trip.km} km)`;
  if (trip.km < 50) {
    li.classList.add('near');
  }
  list.append(li);
}

// Remove the last item again, just to show remove()
list.lastElementChild.remove();

document.getElementById('count').textContent =
  `Showing ${list.children.length} trips.`;
  </script>
</body>
</html>

Tip: Lots of DOM manipulation in a row can be slow on big pages, because the browser may recalculate the layout. For long lists, build the elements first and append them in one go, or use a DocumentFragment.

Make sure the element exists

A script can only find elements that the browser has already parsed. If your script runs in the <head> without defer, getElementById() returns null and the next line fails with “Cannot set properties of null”. Load your scripts with defer or place them at the end of the body, as explained in JavaScript Introduction.

Changing the page when it loads is only half the story. In the next lesson, JavaScript Events, you will run DOM changes in response to clicks, typing and form submissions.

Further reading

Key takeaways

  • The DOM is the browser's live tree of objects built from your HTML.
  • Find elements with getElementById, querySelector and querySelectorAll.
  • Use textContent for text; avoid innerHTML with user input to prevent XSS.
  • Prefer classList to switch CSS classes; use style for calculated values.
  • createElement + append builds new content; remove() deletes it.
  • Run scripts with defer or at the end of the body so elements exist.

Quick quiz

Check what you learned – pick an answer.

1. What does document.querySelector('.item') return when several elements have the class item?

2. Why is textContent safer than innerHTML for showing what a user typed?

3. Which line adds the class open to an element without removing its other classes?

Practice exercise

You have an empty ordered list (ol) with the id "toppers" and an array of student names. Use JavaScript to create one li element per name and append it to the list. Give the first student's li element the class gold so it can be styled differently.

Show a hint

Use forEach((name, index) => …) so you know when index is 0.

Show the solution
<style>.gold { color: goldenrod; font-weight: bold; }</style>
<ol id="toppers"></ol>
<script>
  const names = ['Sowmya', 'Imran', 'Gokul', 'Fathima'];
  const list = document.getElementById('toppers');

  names.forEach((name, index) => {
    const li = document.createElement('li');
    li.textContent = name;
    if (index === 0) {
      li.classList.add('gold');
    }
    list.append(li);
  });
</script>

Progress is saved in this browser only.