This will return the first match (depth first). Conversely, we can check if an element matches a selector:
myElement.matches(‘div.bar’) === true
If we want to get all occurrences, we can use:
const myElements = document.querySelectorAll(‘.bar’)
If we already have a reference to a parent element, we can just query that element’s children instead of the whole document. Having narrowed down the context like this, we can simplify selectors and increase performance.
const myChildElemet = myElement.querySelector(‘input[type=”submit"]’)
// Instead of
// document.querySelector(‘#foo > div.bar input[type="submit"]’)
Then why use those other, less convenient methods like .getElementsByTagName() at all? Well, one important difference is that the result of .querySelector() is not live, so when we dynamically add an element (see section 3 for details) that matches a selector, the collection won’t update.
const elements1 = document.querySelectorAll(‘div’)
const elements2 = document.getElementsByTagName(‘div’)
const newElement = document.createElement(‘div’)
elements1.length === elements2.length // false
Another consideration is that such a live collection doesn’t need to have all of the information up front, whereas .querySelectorAll() immediately gathers everything in a static list, making it less performant.
Working with Nodelists
Now there are two common gotchas regarding .querySelectorAll(). The first one is that we can’t call Node methods on the result and propagate them to its elements (like you might be used from jQuery objects). Rather we have to explicitly iterate over those elements. And this is the other gotcha: the return value is a NodeList, not an Array. This means we can’t call any array methods (e.g. .forEach) on it. We have to convert it to an array first.
// Using Array.from()
// Or prior to ES6
Each element also has a couple of rather self-explanatory read-only properties referencing the "family", all of which are live:
As the Element interface inherits from the Node interface, the following properties are also available:
Where the former only reference elements, the latter (except for .parentElement) can be any kind of node, e.g. text nodes. We can then check the type of a given node like e.g.
myElement.firstChild.nodeType === 3 // this would be a text node
As with any object, we can check a node’s prototype chain using the instanceof operator:
myElement.firstChild.nodeType instanceof Text