Selecting DOM Elements

Find elements on the page with querySelector, querySelectorAll and friends.

Lesson 33 of 56Beginner13 min read

When a browser loads your HTML, it builds a live tree of objects called the DOM, short for Document Object Model. Every element on the page becomes an object that JavaScript can read and change.

This is where JavaScript meets the page. Everything interactive you'll build, from menus to form checks to to-do lists, starts by finding the right element in the DOM. The good news is that you already know the tool for finding elements: the CSS selectors from the CSS Selectors lesson.

The DOM tree

HTML
<body>
  <h1>Shop</h1>
  <ul id="list">
    <li>Apples</li>
    <li>Pears</li>
  </ul>
</body>

To JavaScript, this is a family tree. body has two children, h1 and ul, and the ul has two li children. The whole tree hangs from a single object called document.

The DOM is live. When JavaScript changes it, the page on the screen updates straight away, and when the page changes, the DOM reflects that too.

querySelector and querySelectorAll

  • document.querySelector(selector) returns the first matching element, or null if there isn't one.
  • document.querySelectorAll(selector) returns all matching elements as a NodeList, which is empty if nothing matches.

Any CSS selector works: "#cart", ".card", "nav a", "input[type=email]" or "li:last-child". If you can style it, you can select it.

Other ways to select and move around

  • document.getElementById("cart") selects by id. Note that you don't write the #.
  • element.querySelector(…) searches inside one element instead of the whole page.
  • element.closest(".card") walks up the tree to the nearest matching ancestor, which is very useful with events.
  • element.parentElement, element.children and element.nextElementSibling move around the tree from an element you already have.

NodeLists vs arrays

A NodeList looks like an array. It has .length and .forEach(), but not map or filter. Convert it when you need those methods: [...nodeList] or Array.from(nodeList).

When the result is null

If querySelector finds nothing, it returns null, and trying to use the result throws an error such as Cannot read properties of null. The usual causes are a typo in the selector, a missing # or ., or a script that runs before the HTML has loaded (see Where to Put JavaScript). Logging the result straight after selecting is a quick way to check.

DOM Selecting Syntax

Selecting elements

const title = document.querySelector("h1");
const items = document.querySelectorAll(".item");
const cart = document.getElementById("cart");
const card = button.closest(".card");
const first = list.querySelector("li");

DOM Selecting Summary

  • The DOM is a live tree of objects that represents the page.
  • querySelector finds the first match; querySelectorAll finds every match.
  • Any CSS selector can be used to find elements.
  • closest, parentElement and children move around the tree.
  • A null result usually means a selector typo or a script that ran too early.

DOM Selecting Examples

Each example runs in the page. Edit the code and press Run to see what changes.

Example 1

Finding things on a page

const heading = document.querySelector(".title");
const firstPlant = document.querySelector(".plant");
const allPlants = document.querySelectorAll(".plant");
const onSale = document.querySelector(".plant.sale");
const list = document.getElementById("plants");
const missing = document.querySelector(".nope");

console.log(heading.textContent);
console.log(firstPlant.textContent);
console.log(allPlants.length, "plants");
console.log(onSale.textContent);
console.log(list.children.length);
console.log(missing);
ResultEdit the code, then press Run or Ctrl+Enter
Line-by-line explanation
  1. Line 1The first element with class title.
  2. Line 2Only the first match.
  3. Line 3Every match, as a NodeList of 3.
  4. Line 4Combined class selector, just like CSS.
  5. Line 5By id. Note that there's no #.
  6. Line 6No match returns null.
Example 2

Looping over many elements

const items = document.querySelectorAll("li");

items.forEach((li, i) => {
  console.log(i + 1, li.textContent);
});

const texts = [...items].map(li => li.textContent.split(": ")[0]);
console.log(texts);
ResultEdit the code, then press Run or Ctrl+Enter
Line-by-line explanation
  1. Lines 3 to 5NodeLists have forEach.
  2. Line 7Spread into a real array to use map.
Example 3

Walking the tree with closest

const button = document.querySelector(".buy");

const card = button.closest(".card");
const title = card.querySelector("h3");

console.log(card.dataset.id);
console.log(title.textContent);
console.log(button.parentElement === card);
ResultEdit the code, then press Run or Ctrl+Enter
Line-by-line explanation
  1. Line 3From the button, walk up to the card that contains it.
  2. Line 4Then search inside just that card.
  3. Line 6data-id attributes are available as dataset.id.
  4. Line 8The button's parent is the card.

Common DOM Selecting Mistakes

Forgetting the # or . in querySelector

Don't
document.querySelector("cart");   // looks for a <cart> element
document.getElementById("#cart"); // looks for id="#cart"
Do
document.querySelector("#cart");
document.getElementById("cart");

querySelector needs a full CSS selector; getElementById needs just the id.

Using a NodeList as if it were one element

Don't
document.querySelectorAll(".tab").classList.add("active"); // TypeError
Do
document.querySelectorAll(".tab").forEach(tab => tab.classList.add("active"));

Selecting before the element exists

Don't
// script in <head> without defer
document.querySelector("#app").textContent = "Hi"; // null!
Do
<script src="app.js" defer></script>

DOM Selecting in Real Projects

Selecting is step one of everything

Every interactive feature starts the same way: find the button, the form, the list or the modal. Testing tools (like Playwright) and browser extensions use these exact selectors to find elements too.

DOM Selecting Exercises

Answer each one and check it instantly. If you get stuck, open the hint before the answer.

Fill in the blankseasy

Select the first .card and all .card elements.

const one = document.(".card");
const all = document.(".card");
Multiple choiceeasy

What does document.querySelector(".missing") return when nothing matches?

Multiple choicemedium

You're inside a click handler with the clicked button. How do you get the .product that contains it?

Fix the bugmedium

The code should log the number of .task items (3) and the text of the item with id urgent. Fix the selectors.

const tasks = document.querySelector("task");
const urgent = document.getElementById("#urgent");

console.log(tasks.length);
console.log(urgent.textContent);
ResultEdit the code, then press Run or Ctrl+Enter
Checks
  • Logs 3
  • Logs "Pay rent"
  • No errors

DOM Selecting Quiz

3 questions to check what you learned.

  1. What does DOM stand for?

    • Document Object Model
    • Data Object Manager
    • Digital Output Mode
    • Document Order Map
  2. Which method do NodeLists not have?

    • forEach
    • map
    • length
    • item
  3. How do you search only inside a specific element panel?

    • document.querySelector(panel, "p")
    • panel.find("p")
    • panel.querySelector("p")
    • document.panel("p")

DOM Selecting Challenge

Inventory report

Using DOM selection only:

  1. Count all .item elements and log Items: 4
  2. Count the ones that also have .low and log Low stock: 2
  3. Log the text of the last item using a :last-child selector
ResultEdit the code, then press Run or Ctrl+Enter
Checks
  • Logs "Items: 4"
  • Logs "Low stock: 2"
  • Logs "Butter"
  • Uses querySelectorAll