Quick answer: The JavaScript DOM is the browser’s object model of your page. Select elements with querySelector and querySelectorAll, change them with properties like textContent, classList and setAttribute, create nodes with document.createElement, and insert them with append. Prefer changing classes rather than inline styles so CSS keeps control of appearance.The sections below follow the JavaScript DOM in the order you use it: selecting elements, changing content, creating nodes, attributes and properties, then the ordering mistake behind most JavaScript DOM bugs.

Selecting elements in the JavaScript DOM

const title = document.querySelector("h1");          // first match
const items = document.querySelectorAll(".card");     // all matches (a NodeList)
const byId  = document.getElementById("hero");        // fastest for an id

items.forEach(el => el.classList.add("visible"));     // NodeList is iterable

querySelector takes any CSS selector, so everything from the previous CSS articles applies here. Both queries return null or an empty list when nothing matches, so check before you use the result.

Reading and changing content

title.textContent = "Welcome, Ada";        // text only — safe
title.innerHTML = "<em>Hi</em>";         // parses HTML — risky with user input

const button = document.querySelector("button");
button.classList.add("is-active");
button.classList.toggle("is-open");
button.classList.remove("is-active");
button.dataset.role = "submit";            // sets data-role attribute

Use textContent for anything that might contain user data. innerHTML parses a string as HTML, which opens the door to cross-site scripting if the string came from a form or an API. When you need to change appearance, change a class — the styling stays in CSS where you can reason about it.

Creating and inserting nodes

const list = document.querySelector("#todos");
const li = document.createElement("li");
li.textContent = "Buy milk";
li.classList.add("item");

list.append(li);              // add at the end
list.prepend(li);             // add at the start
li.before(otherLi);           // insert before a sibling
li.remove();                  // take it out of the DOM

For a long list, build the markup off to the side and insert once. Touching the DOM repeatedly forces repeated reflow, so batching thousands of inserts into a single append or a DocumentFragment is markedly faster.

const frag = document.createDocumentFragment();
items.forEach(item => {
  const li = document.createElement("li");
  li.textContent = item.name;
  frag.append(li);
});
list.append(frag);            // one DOM operation for the whole batch

Attributes and properties

Most HTML attributes have a matching DOM property, and the property is usually what you want because it reflects the current state.

const input = document.querySelector("input");
input.value = "hello";                 // current value, not the attribute
input.disabled = true;                 // boolean property
input.setAttribute("aria-label", "Search");  // attribute, for ARIA
input.getAttribute("type");            // "text"

Use properties for state the user controls — value, checked, disabled — and setAttribute for attributes that only exist in markup, such as aria-* and data-*.

Avoiding the black screen of nothing in the JavaScript DOM

The most common beginner error is running script before the DOM exists. Put your <script> at the end of the body, or use defer on a script in the head, so the elements you query are already parsed.

<script src="app.js" defer></script>

Next: events, which make the page react to the user. To learn the DOM with a mentor on real pages, Ampersand Academy teaches web development one-to-one.

Frequently asked questions

What is the difference between textContent and innerHTML?

textContent sets plain text and is safe with any input. innerHTML parses its string as HTML, which allows cross-site scripting if the string includes user data.

Why is querySelector returning null?

Usually the script runs before the element exists in the DOM. Put the script at the end of the body or add the defer attribute so elements are parsed first.

How do I add a CSS class with JavaScript?

Use element.classList.add, remove or toggle. Changing classes keeps styling in CSS and is clearer than setting inline styles from script.

What is a DocumentFragment used for?

It is an offscreen container for building several nodes at once, so you can insert them into the page in a single DOM operation instead of many.

Should I use getElementById or querySelector?

getElementById is faster for a single id, while querySelector accepts any CSS selector and is more flexible. Both return null when nothing matches, so check the result.

Last updated on · Written by