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

Selecting elements

Reading43mLesson 1 of 3 in this module

What you'll learn

  • Select and change elements on a page
  • Use querySelector and querySelectorAll with CSS selectors
  • Change text with textContent and classes with classList
  • Explain why textContent is safer than innerHTML for untrusted data

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.

HTML
<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:

JavaScript
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.
JavaScript
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:

JavaScript
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:

JavaScript
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:

CSS
.highlight { background: #fff3b0; }
JavaScript
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:

JavaScript
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.

Key terms (6)

DOM
The Document Object Model: the browser's live tree of objects for the page, which JavaScript reads and edits through document.
querySelector
A method that returns the first element matching a CSS selector, or null when nothing matches.
NodeList
The list of elements returned by querySelectorAll, which you can loop over with for...of or forEach.
textContent
A property holding an element's plain text; setting it shows the string as text, never as HTML.
classList
An element property with add, remove, toggle and contains methods for switching CSS classes.
cross-site scripting (XSS)
A security hole where untrusted text inserted as HTML lets someone run their own scripts on your page.

Recap

  • The DOM is the browser's live tree of the page, and document is the way in.
  • querySelector returns the first match or null; querySelectorAll returns every match.
  • Change text with textContent, classes with classList and attributes with properties or setAttribute.
  • Prefer classes over inline styles and textContent over innerHTML.
  • Run scripts after the elements exist: at the end of the body or with defer.
Also in this lesson: