The DOM: Selecting Elements
When a browser loads HTML, it builds a tree of objects in memory called the Document Object Model, or DOM. Each tag becomes an object JavaScript can read and change. The first step in any page interaction is finding the right element — this lesson covers every way to do it.
The document tree
Given this HTML:
<body> <h1 id="title">Recipes</h1> <ul class="list"> <li class="item">Soup</li> <li class="item featured">Salad</li> </ul> </body>
the browser creates a tree: document at the top, then <html>, <body>, and so on. Each element is a node with a parent, children and siblings. The global document object is your entry point to all of it.
querySelector and querySelectorAll
These take any CSS selector — the same syntax you use in stylesheets:
querySelectorreturns the first matching element, ornullif none match.querySelectorAllreturns a NodeList of all matches (possibly empty).
Working with a NodeList
A NodeList isn't an array, but it supports forEach, length, indexing and for…of. For other array methods, convert it first:
Older selection methods
| Method | Returns | Notes |
|---|---|---|
getElementById("title") | One element or null | Very fast; no # in the argument |
getElementsByClassName("item") | Live HTMLCollection | No dot in the argument |
getElementsByTagName("li") | Live HTMLCollection |
A live collection updates automatically as the page changes, which can cause surprises in loops that add or remove elements. querySelectorAll returns a static snapshot. Most modern code uses querySelector/querySelectorAll for consistency.
Searching inside an element
Every element has its own querySelector methods that only search its descendants — useful when a page has repeated components:
Walking the tree
From any element, you can move to related elements:
| Property / method | Gives |
|---|---|
parentElement | The parent element |
children | Child elements |
firstElementChild, lastElementChild | First/last child element |
nextElementSibling, previousElementSibling | Neighbouring elements |
closest(selector) | The nearest ancestor (or itself) matching a selector |
matches(selector) | Whether the element matches a selector |
closest is especially handy in event handlers, to get from the clicked element up to the component it belongs to (lesson 45).
Always check for null
If a selector doesn't match anything — a typo, or the script ran before the element existed — querySelector returns null, and using the result crashes with "Cannot read properties of null". Check, or use optional chaining:
const banner = document.querySelector("#promo-banner"); if (banner) { banner.hidden = false; } document.querySelector("#maybe")?.classList.add("active");
And make sure your script runs after the HTML exists, using defer or type="module" (lesson 02).
Try it yourself
Change the selectors to highlight different elements: