Selecting Elements

Before you can modify an element, you need to select it. The DOM gives you several methods to find elements. Two of them, querySelector and querySelectorAll, handle the widest range of cases, so we will start there.

querySelector and querySelectorAll

The querySelector method returns the first element matching a CSS selector:

// Select by tag name
const heading = document.querySelector("h1");

// Select by class
const menu = document.querySelector(".navigation");

// Select by ID
const sidebar = document.querySelector("#sidebar");

// Select by attribute
const submitBtn = document.querySelector('[type="submit"]');

// Select with complex selectors
const firstItem = document.querySelector("ul.menu > li:first-child");

If no element matches, querySelector returns null:

const missing = document.querySelector(".nonexistent");
console.log(missing); // null

The querySelectorAll method returns all matching elements as a NodeList:

// Select all paragraphs
const paragraphs = document.querySelectorAll("p");
console.log(paragraphs.length);  // Number of <p> elements

// Select all elements with a class
const buttons = document.querySelectorAll(".btn");

// Iterate over results
paragraphs.forEach((p) => {
  console.log(p.textContent);
});

Legacy Selection Methods

Before querySelector existed, developers used a separate method for each kind of selector:

// Select by ID - returns single element or null
const header = document.getElementById("header");

// Select by class - returns live HTMLCollection
const items = document.getElementsByClassName("item");

// Select by tag - returns live HTMLCollection
const divs = document.getElementsByTagName("div");

// Select by name attribute - returns live NodeList
const options = document.getElementsByName("choice");

You will see these methods a lot in existing code. The main difference from querySelector is that getElementsByClassName and getElementsByTagName return live collections. A live collection updates on its own when the DOM changes. querySelectorAll returns a static snapshot instead, so it does not update.

Searching Within Elements

You can call querySelector on any element, not just document:

const nav = document.querySelector("nav");

// Search only within nav
const navLinks = nav.querySelectorAll("a");
const firstLink = nav.querySelector("a");

Searching inside an element like this is useful when you work with components or with one section of a page:

const cards = document.querySelectorAll(".card");

cards.forEach((card) => {
  // Each search is scoped to this card
  const title = card.querySelector(".card-title");
  const body = card.querySelector(".card-body");
  console.log(title.textContent);
});