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.| Method | Returns | Live? |
|---|---|---|
| querySelector | Element | null | — |
| querySelectorAll | static NodeList | No |
| getElementById | Element | null | — |
| getElementsByClassName | live HTMLCollection | Yes |
| getElementsByTagName | live HTMLCollection | Yes |
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.