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
| Method | Returns |
|---|---|
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()andcontains()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')andgetAttribute()work with any attribute. Common ones also exist as properties:img.src,link.href,input.value,button.disabled.el.datasetreadsdata-*attributes:<li data-price="250">givesli.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
- developer.mozilla.org/en-US/docs/Web/API/Document_Object_Model
- developer.mozilla.org/en-US/docs/Web/API/Document/querySelector
- developer.mozilla.org/en-US/docs/Web/API/Node/textContent
- developer.mozilla.org/en-US/docs/Web/API/Element/classList
- developer.mozilla.org/en-US/docs/Web/API/Document/createElement
