Skip to main content
Back to module
JavaScript Essentials · Working with the DOM

Selecting elements

Reading43mLesson 1 of 3 in this module

Find elements on a page with querySelector and change their text, classes and attributes.

Why this matters

HTML describes what is on a page; CSS describes how it looks. JavaScript makes it change: a counter going up, a menu opening, an error message appearing under a form field. To change anything, you first have to get hold of it. This lesson is about finding elements on a page and editing them, which is step one of every interactive feature you will build.

The DOM

When the browser loads your HTML, it builds a tree of objects in memory called the DOM (Document Object Model). Every tag becomes a node in that tree, and JavaScript can read and edit those nodes. The entry point is the global document object.

<body>
  <h1 id="title">My shop</h1>
  <p class="intro">Welcome!</p>
  <ul>
    <li class="item">Pens</li>
    <li class="item">Paper</li>
  </ul>
</body>

Change the DOM and the page updates straight away; you never edit the HTML file itself.

querySelector and querySelectorAll

Both take a CSS selector, the same syntax you already know from stylesheets:

const title = document.querySelector("#title");     // by id
const intro = document.querySelector(".intro");     // first match by class
const firstItem = document.querySelector("ul li");  // descendant selector
const items = document.querySelectorAll(".item");   // ALL matches
  • querySelector returns the first matching element, or null if nothing matches.
  • querySelectorAll returns a NodeList of every match (possibly empty). You can loop over it with for...of or forEach.
for (const item of items) {
  console.log(item.textContent);
}
items.length;  // 2

You may also meet older methods such as getElementById("title") and getElementsByClassName("item"). They work, but querySelector covers every case with one consistent syntax.

Changing what is on the page

Once you have an element, you can change it:

title.textContent = "Spring sale";       // replace the text
intro.style.color = "darkgreen";          // set one inline style
title.setAttribute("data-state", "sale"); // set any attribute
const link = document.querySelector("a");
link.href = "https://example.com";        // common attributes are properties

textContent vs innerHTML

textContent sets plain text. innerHTML parses the string as HTML:

intro.textContent = "<b>Hi</b>";  // shows the characters <b>Hi</b>
intro.innerHTML = "<b>Hi</b>";    // shows bold Hi

Use textContent for anything that came from a user or a server. Putting untrusted text into innerHTML lets someone inject their own HTML and scripts into your page, a security hole called cross-site scripting (XSS). Use innerHTML only for markup you wrote yourself.

Classes are better than inline styles

Rather than setting lots of style properties, define a class in CSS and switch it on and off with classList:

.highlight { background: #fff3b0; }
firstItem.classList.add("highlight");
firstItem.classList.remove("highlight");
firstItem.classList.toggle("highlight");    // add if missing, remove if present
firstItem.classList.contains("highlight");  // true or false

This keeps styling in CSS where it belongs, and one class can change many properties at once.

A worked example

Mark every item and show a count:

const items = document.querySelectorAll(".item");
for (const item of items) {
  item.classList.add("highlight");
}
document.querySelector(".intro").textContent =
  `There are ${items.length} items`;

Where to put your script

A script can only select elements that already exist. If your <script> is in the <head>, the body has not been built yet and querySelector returns null. Two fixes:

  • Put the <script> at the end of the <body> (what this course does), or
  • Use <script src="app.js" defer></script> in the head, which waits until the page is parsed.

Common mistakes

  • Forgetting the # or . querySelector("title") looks for a <title> tag, not id="title".
  • Using the result of querySelector without checking it. If it is null, title.textContent = ... throws "Cannot set properties of null". Check your selector in the console.
  • Treating a NodeList like one element. items.textContent = "x" does nothing useful; loop over the items.
  • Running the script before the elements exist. Move it to the end of the body or use defer.
  • Using innerHTML with user input. Use textContent.

Quick recap

  • The DOM is the browser's live tree of your page; document is the way in.
  • querySelector returns the first match or null; querySelectorAll returns all matches.
  • Change text with textContent, classes with classList, attributes with properties or setAttribute.
  • Prefer classes over inline styles and textContent over innerHTML.

Try it

Open the Do tab. A small shop page is ready; you will write the JavaScript that changes its title, highlights every item and shows the item count.

Also in this lesson: