Selecting Elements

Find anything on the page. The first step to DOM manipulation.

querySelector

Find the FIRST element matching a CSS selector.

// By class:
const card = document.querySelector(".card");

// By ID:
const app = document.querySelector("#app");

// By tag:
const firstParagraph = document.querySelector("p");

// Complex selectors:
const activeLink = document.querySelector("nav a.active");
const firstItem = document.querySelector("ul > li:first-child");

querySelector accepts any valid CSS selector. Returns the first match or null if nothing is found.

1 / 2

querySelectorAll

Find ALL elements matching a selector.

// Returns a NodeList (array-like, not a true array):
const items = document.querySelectorAll("li");
items.length;   // number of matches
items[0];       // first element
items[2];       // third element

// NodeList supports forEach:
items.forEach(item => {
  item.classList.add("styled");
});

// Convert to array for map/filter/reduce:
const arr = [...items]; // spread
// or: Array.from(items)

const active = arr.filter(el => el.classList.contains("active"));
const texts = arr.map(el => el.textContent);

💡 querySelectorAll returns a staticNodeList — a snapshot. If elements are added/removed later, the NodeList doesn't update.

By ID, Class, Tag

Older methods — still useful in specific cases.

// By ID (fastest — IDs are unique):
const el = document.getElementById("app");
// No # prefix! Returns element or null.

// By class name (returns live HTMLCollection):
const cards = document.getElementsByClassName("card");
// No dot prefix!

// By tag name (returns live HTMLCollection):
const paragraphs = document.getElementsByTagName("p");

// These return LIVE collections — they auto-update!
// If you add a <p>, paragraphs.length increases.
MethodReturnsLive?
querySelectorElement | null
querySelectorAllstatic NodeListNo
getElementByIdElement | null
getElementsByClassNamelive HTMLCollectionYes
getElementsByTagNamelive HTMLCollectionYes

DOM Traversal

Navigate between related elements.

const el = document.querySelector(".current");

// Parent:
el.parentElement;         // direct parent element
el.closest(".wrapper");   // nearest ancestor matching selector

// Children:
el.children;              // direct child elements (HTMLCollection)
el.firstElementChild;     // first child element
el.lastElementChild;      // last child element
el.childElementCount;     // number of children

// Siblings:
el.nextElementSibling;    // next sibling element
el.previousElementSibling; // previous sibling element

// Example — highlight all siblings:
let sibling = el.parentElement.firstElementChild;
while (sibling) {
  if (sibling !== el) sibling.classList.add("dim");
  sibling = sibling.nextElementSibling;
}

⚠️ Use parentElement / children (elements only), not parentNode / childNodes (includes text/comment nodes).

Live vs Static

Some collections update automatically, others don't.

// STATIC (snapshot — doesn't update):
const items = document.querySelectorAll("li");
console.log(items.length); // 3

document.querySelector("ul").innerHTML += "<li>New</li>";
console.log(items.length); // still 3! (stale)

// LIVE (auto-updates):
const items2 = document.getElementsByTagName("li");
console.log(items2.length); // 3

document.querySelector("ul").innerHTML += "<li>New</li>";
console.log(items2.length); // 4! (auto-updated)

// ⚠️ Live collections can cause infinite loops:
// for (let i = 0; i < liveList.length; i++) {
//   liveList[i].className = "x"; // if this adds matches...
// }
// Prefer static querySelectorAll for iteration.

FAQ

Common questions about selecting elements.