Selecting DOM Elements
Checking access...
Before you can manipulate an element, you need to select it. JavaScript provides several methods to find elements in the DOM tree.
Selecting by ID
The fastest way to select a single element:
<div id="header">Welcome</div>const header = document.getElementById("header");console.log(header); // <div id="header">Welcome</div>- Returns a single element (or
nullif not found) - IDs must be unique per page — this always returns one result
- This is the fastest selector method
Selecting by Class Name
<div class="card">Card 1</div><div class="card">Card 2</div>const cards = document.getElementsByClassName("card");console.log(cards); // HTMLCollection(2) [div.card, div.card]console.log(cards[0]); // first elementconsole.log(cards.length); // 2⚠️ getElementsByClassName returns a live HTMLCollection — it updates automatically when the DOM changes. This can lead to unexpected behaviour if you’re also modifying the DOM.
Selecting by Tag Name
<p>First</p><p>Second</p><p>Third</p>const paragraphs = document.getElementsByTagName("p");console.log(paragraphs.length); // 3Also returns a live HTMLCollection.
Modern Selectors: querySelector and querySelectorAll
These methods accept any CSS selector, making them the most flexible and commonly used:
querySelector — Returns First Match
const firstButton = document.querySelector(".btn");const header = document.querySelector("#header");const firstListItem = document.querySelector("ul li:first-child");const link = document.querySelector("a[target='_blank']");const nested = document.querySelector(".container .content p");Returns a single element or null.
querySelectorAll — Returns All Matches
const allButtons = document.querySelectorAll(".btn");const allParagraphs = document.querySelectorAll("p");const oddRows = document.querySelectorAll("tr:nth-child(odd)");const checkedInputs = document.querySelectorAll("input:checked");Returns a static NodeList — it does NOT update when the DOM changes.
Tip
Unless you need a live collection (rare), prefer querySelector/querySelectorAll. They’re more flexible and their static behaviour is less surprising.
NodeList vs HTMLCollection
| Feature | NodeList (static) | HTMLCollection (live) |
|---|---|---|
| Live? | No (snapshot) | Yes (auto-updates) |
forEach | ✅ Built-in | ❌ Must convert |
length | ✅ | ✅ |
Bracket access [0] | ✅ | ✅ |
item(index) | ✅ | ✅ |
| Convert to array | [...nl] or Array.from(nl) | [...col] or Array.from(col) |
Live collection gotcha:
const liveItems = document.getElementsByClassName("item");console.log(liveItems.length); // 3
// Remove an item from the DOMliveItems[0].remove();
console.log(liveItems.length); // 2 — live collection updated automatically!Scoped Selection
You can scope selection to a specific element instead of the whole document:
const container = document.getElementById("container");
// Only search within containerconst items = container.querySelectorAll(".item");const header = container.querySelector("h2");This is more efficient and avoids matching elements outside your intended scope.
Selecting Multiple Elements by Data Attributes
<button data-action="save">Save</button><button data-action="delete">Delete</button><button data-action="edit">Edit</button>const saveBtn = document.querySelector('[data-action="save"]');const allActionBtns = document.querySelectorAll("[data-action]");Checking if Elements Exist
Always check that selections succeeded before manipulating:
const el = document.querySelector(".maybe-exists");
// ✅ Safeif (el) { el.textContent = "Found it!";}
// ❌ Dangerous — TypeError if el is nullel.textContent = "Found it!"; // crashes if el is nullCommon Selection Patterns
<!-- HTML to select from --><div id="app"> <ul class="list"> <li class="item active">Item 1</li> <li class="item">Item 2</li> <li class="item">Item 3</li> </ul> <form id="login-form"> <input type="email" name="email" /> <input type="password" name="password" /> <button type="submit">Log In</button> </form></div>// Select by IDconst app = document.querySelector("#app");const form = document.getElementById("login-form");
// Select by classconst items = document.querySelectorAll(".item");const activeItem = document.querySelector(".item.active"); // CSS compound selector
// Select by attributeconst emailInput = document.querySelector('input[name="email"]');const submitBtn = document.querySelector('button[type="submit"]');
// Select by relationshipconst firstItem = document.querySelector(".list .item:first-child");const lastItem = document.querySelector(".list .item:last-child");
// Select form elementsconst formElements = document.forms["login-form"].elements;console.log(formElements["email"]); // the email inputConverting Collections to Arrays
const items = document.querySelectorAll(".item");
// Option 1: Spread operatorconst itemArray = [...items];
// Option 2: Array.fromconst itemArray2 = Array.from(items);
// Option 3: Array.from with mapconst texts = Array.from(items, (el) => el.textContent);Once converted, you can use all array methods (map, filter, reduce, find):
const items = document.querySelectorAll(".item");const activeTexts = [...items] .filter((item) => item.classList.contains("active")) .map((item) => item.textContent);Performance Notes
In modern browsers, performance differences between selectors are negligible for most use cases. General guidance:
getElementByIdis fastest for single elements with IDsquerySelector/querySelectorAllare preferred for everything else (flexibility, readability)- Avoid selecting by tag name inside loops — cache the selection
// ✅ Good — cache the selectionconst buttons = document.querySelectorAll(".btn");buttons.forEach((btn) => { /* ... */ });
// ❌ Bad — re-querying on every iterationdocument.querySelectorAll(".btn").forEach((btn) => { /* ... */ });Quick Reference
| Method | Returns | Live? | Example |
|---|---|---|---|
getElementById(id) | Element or null | — | getElementById("header") |
getElementsByClassName(name) | HTMLCollection | ✅ Live | getElementsByClassName("card") |
getElementsByTagName(tag) | HTMLCollection | ✅ Live | getElementsByTagName("p") |
querySelector(css) | Element or null | — | querySelector(".card:first-child") |
querySelectorAll(css) | NodeList | ❌ Static | querySelectorAll(".card") |
Practice Exercises
Create an HTML page with a
<div id="app">containing three<p>elements with different classes. Use each selection method to select and log them.On any webpage, use the console to select all links (
<a>tags). How many are there? Filter to only external links (those starting with “http”).Build a “select by data attribute” example: create buttons with
data-color="red",data-color="blue", etc. UsequerySelectorAllto select all blue buttons and log them.