JS Tip of the Day: Finding Elements in the DOM

Finding Elements in the DOM
Level: Beginner

Historically, to access HTML elements from within a web page, 3 popular methods were often used:

  • getElementById()
  • getElementsByClassName()
  • getElementsByTagName()

getElementById() returns a single element reference based on an exact match with an id attribute in an HTML element while getElementsByClassName() and getElementsByTagName() returns iterable array-like lists (HTMLCollection objects) of 0 or more elements matching a one or more class names or a single tag name respectively.

<div id="outer">
  <div class="inner">
    <span class="inner text">space</span>
  </div>
</div>

<script>
console.log(document.getElementById('outer'));
// <div id="outer">

console.log(document.getElementsByClassName('inner'));
// HTMLCollection[ <div class="inner">, <span class="inner text"> ]

console.log(document.getElementsByTagName('div'));
// HTMLCollection[ <div id="outer">, <div class="inner"> ]
</script>

These methods can work well, but are also very broad in what they can target individually. While you can access all elements with a certain class applied or all elements of a certain tag, it’s harder to mix the two, for example get just the “div” elements with the class “inner”. That’s where the newer query methods can come in handy.

With the popularity of JQuery and its ability to easily target elements through a CSS-style selectors, two new methods were added to provide similar functionality in the standard web API:

  • querySelector()
  • querySelectorAll()

These accept one or more comma-separated CSS queries and returns any matches to those queries found in the DOM. The difference between querySelector() and querySelectorAll() is that querySelector() will only return one element (the first if multiple are found) while querySelectorAll() will return multiple in iterable array-like lists (NodeList objects).

<div id="outer">
  <div class="inner">
    <span class="inner text">space</span>
  </div>
</div>

<script>
console.log(document.querySelector('#outer'));
// <div id="outer">

console.log(document.querySelectorAll('.inner'));
// NodeList[ <div class="inner">, <span class="inner text"> ]

console.log(document.querySelectorAll('div'));
// NodeList[ <div id="outer">, <div class="inner"> ]

console.log(document.querySelectorAll('div.inner'));
// NodeList[ <div class="inner"> ]
</script>

As you can see, these two methods easily provide the same functionality as the others, plus provide more flexibility and specificity in element targeting. Chances are, if you’re looking for elements in the DOM, these are going to be your go-tos.

Also, each of the methods covered, while being used with document in the examples, will also work off of any element reference if you only wish to find elements that are descendants of that element.

// only find divs inside #outer
let outer = document.getElementById('outer');

console.log(outer.getElementsByTagName('div'));
// HTMLCollection[ <div class="inner"> ]

console.log(outer.querySelectorAll('div'));
// NodeList[ <div class="inner"> ]

Though this can also be easily be done with a single call using a query.

console.log(document.querySelectorAll('#outer div'));
// NodeList[ <div class="inner"> ]

More info:

Can querySelector and querySelectorAll be applied to specific elements to find specific nodes that are children or must they always reference the “document”?

Yup! “each of the methods covered” includes the query methods. I’ll add a query example with the other one to make that more clear :wink: