Finding elements on the page
The browser turns a page's HTML code into a set of objects: every tag becomes an object with properties and methods. This structure is called the DOM (Document Object Model). Through it, JavaScript reads and changes the page.
The examples in this chapter are small pages. Below the code you see the result: the page itself and everything printed with console.log().
querySelector
The whole page is available through the document object. Its querySelector() method finds an element by a CSS selector:
<h1>Hello, world!</h1>
<script>
const heading = document.querySelector('h1');
console.log(heading.textContent); // Hello, world!
</script>The textContent property holds the element's text.
Selectors
The selectors are the same as in CSS: a tag name, # for an id and a dot for a class. Complex selectors work too, such as ul li or input[type="email"]:
<p id="intro">Introduction</p>
<p class="note">Note</p>
<script>
console.log(document.querySelector('#intro').textContent); // Introduction
console.log(document.querySelector('.note').textContent); // Note
</script>If several elements match, querySelector() returns the first one.
querySelectorAll
The querySelectorAll() method returns all matching elements. You can loop over the result with for...of and get the count from length:
<ul>
<li>Tea</li>
<li>Coffee</li>
<li>Juice</li>
</ul>
<script>
const items = document.querySelectorAll('li');
console.log(items.length); // 3
for (const item of items) {
console.log(item.textContent);
}
</script>This is not an array but an array-like list. If you need map() or filter(), turn it into an array: Array.from(items).
Searching inside an element
Both methods exist not only on document but on every element. Then the search happens only inside it:
<ul id="drinks">
<li>Tea</li>
</ul>
<ul id="food">
<li>Bread</li>
<li>Cheese</li>
</ul>
<script>
const food = document.querySelector('#food');
console.log(food.querySelectorAll('li').length); // 2
</script>Searching upwards: closest
The closest() method searches the other way — among the element's parents, that is, the tags it sits inside. It returns the nearest parent that matches the selector:
<div class="card">
<h2>Laptop</h2>
<button>Buy</button>
</div>
<script>
const button = document.querySelector('button');
const card = button.closest('.card');
console.log(card.querySelector('h2').textContent); // Laptop
</script>When nothing is found
When there is no matching element, querySelector() returns null:
<p>This page has no heading.</p>
<script>
const heading = document.querySelector('h1');
console.log(heading); // null
</script>Accessing a property of null throws an error, so it is worth checking the result: if (heading) { ... }.
Common mistake
A script runs at the point in the page where it is written. If you put it before an element, the element does not exist yet and the search returns null. That is why scripts are placed at the end of the page, after all the markup, or the script tag gets the defer attribute — then the browser runs it after the page has loaded.