the short answer
Use document.querySelector() with a CSS selector to get the first element that matches, and document.querySelectorAll() to get every match. For one element with an id, document.getElementById() also works. Once you have the element, you can read it or change it.
To select an element on a web page with JavaScript, use document.querySelector() and give it a CSS selector. It gives back the first element that matches. To get every match, use document.querySelectorAll():
const heading = document.querySelector("h1");
const pets = document.querySelectorAll(".pet");Selecting is always the first step. You cannot change a heading, hide a message or react to a button until your code has found it. This guide explains what the DOM is, the three ways of selecting you will use most, how to handle a selector that finds nothing, and the mistakes that trip up nearly every beginner.
These examples need a real web page to work on, so they are shown rather than run here. You can try every one in your browser’s console, and there is a way to try it on this very page further down.
What the DOM is
When a browser loads a page, it reads the HTML and builds a live copy of it in memory. That copy is a tree of objects: the page at the top, then the <html> element, then <head> and <body>, then everything inside them. It is called the DOM, short for Document Object Model.
JavaScript cannot touch your HTML file. It works with the DOM instead. Change the DOM and the page on screen changes straight away.
document is your way in. It stands for the whole page, and every selecting method starts from it.
The page used in this guide
Every example below works on this small page:
<h1 id="title">Pet shop</h1>
<p class="note">Open every day.</p>
<ul id="pets">
<li class="pet">Cat</li>
<li class="pet">Dog</li>
<li class="pet sold">Fish</li>
</ul>
<button>Adopt</button>querySelector: the first match
document.querySelector() takes a CSS selector, written as text in quotes, and gives back the first element that matches. textContent then reads the words inside it:
const title = document.querySelector("#title");
console.log(title.textContent);Pet shopThe selector is exactly the kind you write in CSS. The ones you will use most:
"h1"finds an element by its tag name.".note"finds an element by its class. Note the dot."#pets"finds an element by its id. Note the hash."#pets .pet"finds a.petsomewhere inside#pets.".pet.sold"finds an element that has both classes."li:first-child"finds anlithat is the first child of its parent.
Because querySelector() stops at the first match, querySelector(".pet") gives you the Cat item, even though there are three items with that class.
querySelectorAll: every match
document.querySelectorAll() gives back every element that matches, in the order they appear on the page. The result is called a NodeList. It has a length, and you can loop over it:
const pets = document.querySelectorAll(".pet");
console.log(pets.length);
pets.forEach((pet) => console.log(pet.textContent));3
Cat
Dog
FishYou can also pick one item by its position, counting from 0. pets[2].textContent is "Fish".
If nothing matches, you get an empty NodeList with a length of 0, not an error. That makes querySelectorAll() safe to loop over even when the page has nothing to find.
getElementById: the older way to find an id
document.getElementById() finds one element by its id. You give it the id on its own, with no hash:
const list = document.getElementById("pets");
console.log(list.children.length);3It does the same job as querySelector("#pets"). You will see it a lot in older code and tutorials. Either is fine, but using querySelector() everywhere means you only have one method to remember.
Two more you may meet
getElementsByClassName() and getElementsByTagName() also exist. They give back a live list that updates by itself when the page changes, which can surprise you inside a loop. Beginners are better off with querySelectorAll(), whose list stays exactly as it was when you asked.
Searching inside an element
Every element has its own querySelector() and querySelectorAll(). Call them on an element and the search stays inside it:
const list = document.querySelector("#pets");
const sold = list.querySelector(".sold");
console.log(sold.textContent);FishThis is useful on big pages, where the same class can appear in many places. Find the right section first, then search inside it.
When nothing matches: null
If querySelector() cannot find a match, it gives back null, which means “nothing”. The trouble starts on the next line, when you try to use it:
const missing = document.querySelector("#price");
console.log(missing);
console.log(missing.textContent);The first log shows null. The second stops the script. Chrome and Edge report it as TypeError: Cannot read properties of null (reading 'textContent'). Firefox words it differently, but it means the same thing: you asked a missing element for its text.
When an element might not be there, check before you use it:
const price = document.querySelector("#price");
if (price) {
console.log(price.textContent);
} else {
console.log("No price on this page");
}No price on this pageYour script might run too early
A browser reads a page from top to bottom. If your <script> tag sits in the <head>, it runs before the <body> has been read, so there is nothing to select yet and every querySelector() gives back null.
There are two simple fixes:
- Put the script at the end of the body, just before
</body>. - Add
deferto the script tag, like<script src="app.js" defer></script>. The browser then waits until the page is read before running it.
Common mistakes
Forgetting the dot or the hash
querySelector("pets") looks for a tag called pets, which does not exist, so it gives back null. Ids need # and classes need . in a selector.
Putting a hash in getElementById
getElementById("#pets") looks for an id that literally starts with a hash. It finds nothing and gives back null. The hash belongs in selectors only.
Treating a NodeList as one element
Asking a whole NodeList for its textContent gives undefined, because the list itself has no text. Loop over it, or pick one item, like [0].
Calling array methods on a NodeList
pets.map(...) stops with TypeError: pets.map is not a function. A NodeList has forEach but not map or filter. Wrap it first: Array.from(pets).map(...).
Getting the capital letters wrong
JavaScript cares about capitals. document.queryselector stops with TypeError: document.queryselector is not a function. It is querySelector, with a capital S.
Using the same id twice
An id should appear once per page. If two elements share one, getElementById() quietly gives you the first and ignores the other. Use a class for anything that repeats.
Try it on this page
You are reading a web page right now, so you can practise on it. Open your browser’s console, which is Ctrl, Shift and J in Chrome or Edge on Windows, or Cmd, Option and J in Chrome on a Mac. Then type:
document.querySelector("h1").textContentThe console shows the title of this article. Now count the section headings on this page:
document.querySelectorAll("h2").lengthNothing you type there can break the page for anyone else, and a refresh puts everything back.
If the console is new to you, our guide to JavaScript console.log() explains how to open and use it.
A short exercise
Using the pet shop page from earlier, log the name of every pet that has not been sold. Your output should be:
Cat
DogHint: CSS has a :not() selector, which matches elements that do not match the selector inside the brackets.
One possible answer
const available = document.querySelectorAll(".pet:not(.sold)");
available.forEach((pet) => console.log(pet.textContent));Related reading
- JavaScript console.log() explained, for seeing what your selections found.
- What does a computer program do?, if you are new to code altogether.
Your next step
Selecting elements is the gateway to everything interactive on the web. Gwecode’s JavaScript Level 2 starts right here, with a live page next to your code, then moves on to changing words, reacting to clicks and building whole lists from data. Its level check is a working shopping list app. Every lesson is free and runs in your browser. Create a free account to keep your progress, then start with the lesson below.
practise this · javascript · lessonMeet the pagestart the lessonquestions
What is the DOM?
DOM stands for Document Object Model. It is the browser’s live copy of a web page, built from the HTML as a tree of objects that JavaScript can read and change.
What is the difference between querySelector and getElementById?
getElementById only finds an element by its id. querySelector finds an element using any CSS selector, including an id. Both give back the first match, or null if there is none.
Why does querySelector return null?
Nothing on the page matched the selector when that line ran. Check the spelling, the # or the dot, and that your script runs after the HTML it is looking for.
Is a NodeList an array?
Not quite. You can loop over it with forEach or for...of, but array methods like map are missing. Array.from() turns it into a real array.
Can I select elements inside another element?
Yes. Call querySelector or querySelectorAll on that element instead of on document, and the search stays inside it.
