Whenever we need to perform DOM manipulation, we’re all quick to reach for jQuery. However, the vanilla JavaScrpt DOM API is actually quite capable in its own right, and since IE < 11 has been officially abandoned, it can now be used without any worries.
- querying and modifying the DOM,
- modifying classes and attributes,
- listening to events, and
I’ll finish off by showing you how to create your own super slim DOM-library that you can drop into any project. Along the way, you’ll learn that DOM manipulation with vanilla JS is not rocket science and that many jQuery methods in fact have direct equivalents in the native API.
So let’s get to it …
DOM Manipulation: Querying the DOM
Please note: I won’t explain the Vanilla DOM API in full detail, but only scratch the surface. In the usage examples, you may encounter methods I haven’t introduced explicitly. In this case just refer to the excellent Mozilla Developer Network for details.
The DOM can be queried using the .querySelector() method, which takes an arbitrary CSS selector as an argument:
const myElement = document.querySelector('#foo > div.bar')
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') document.body.appendChild(newElement) 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.