The JavaScript ecosystem is always evolving and it is time for another wave of the future.
We all loved it when jQuery was baked into browsers as document.querySelector()
and document.querySelectorAll()
. The DOM methods make accessing the DOM a lot better.
Recently, I have had some experience that practically proved to me that using both document.querySelector()
and document.querySelectorAll()
is sticking to the distant past while missing many juicy features in Javascript.
Using document.querySelector()
and document.querySelectorAll()
means you can’t destructure the DOM, access the DOM consistently, simplify multiple selections and reduce typing difficulties. Now, let’s dive deeper so that you can realize all you’re missing already.
But wait! If you don’t really understand what querySelector() and querySelectorAll() are, and you want to learn more about them; check out the video tutorial below: JavaScript DOM manipulation
Inconsistent methods
document.querySelector()
and document.querySelectorAll()
are not consistent in selecting the DOM. One selects the first instance of the target selector while the other selects all instances of the target selector. That means one is used to select an individual element while the other is used to select a group of elements.
So you can’t use both interchangeably. You have to keep on switching from one to another depending on what you want to select.
// Select the first element of the class .post
const post = document.querySelector('.post');
// Select all elements of the class .post
const posts = document.querySelectorAll('.post');
Now, let me show you a better way to do it. I just built a UI library called koras.jsxthat comes with $select()
which can use in place of both document.querySelector()
and document.querySelectorAll()
in JavaScript and below is how to use it.
//select all instances of class .post
const posts = $select('.post');
//select the first instance of class post
const firstPost = $select('.post[0]');
//Doing the same with querySelector
const posts = document.querySelectorAll('.post');
const firstPost = posts[0];
How cool is that? And it just works for the use cases of both document.querySelector()
and document.querySelectorAll()
.
Selection by index
You can select an element among grouped elements at any position.
//select 6th instance of class post
$select('.post[5]')
//select 7th instance of div elements
$select('div[6]')
Deleting elements
You can delete elements with $select()
like:
//Delete only the instance of .post with index is equal to 2
$select('.post[delete|i=2]');
//delete all instances of .post with index greater than 2
$select('.post[delete|i>2]');
Adding attributes
You can add attributes to elements with $select()
like:
$select('.post[add|class=hidden]');
$select('.post[add|id=2]');
$select('.post[add|class=flex bold]')
You can remove attributes from elements with $select()
like:
$select('.post[remove|class=hidden]');
$select('.post[add|style=1px solid red]');
$select('.post[remove|id=2]');
$select('.post[remove|class=flex bold]')
$select('.post[remove|style]');
DOM destructuring
DOM destructuring is one of the features shipped in es6 but you would be surprised you can’t destructure the elements selected with document.querySelector()
and document.querySelectorAll()
.
Not working:
const [posts, comments] = document.querySelectorAll('.post, .comment');
Solution:
const [posts, comments] = $select('.post, .comment');
Can you see that? document.querySelectAll()
doesn’t support DOM destructuring. That means you’re missing out on destructuring the DOM. No! That is not cool at all so you have to start using $select()
.
Repetitive methods
Using document.querySelect()
or document.querySelectorAll()
forces you to repeat themselves unnecessarily because they don’t support DOM destructuring and that makes it a bit messy to maintain JavaScript code.
Won’t work
const [audio, posts, comments] = document.querySelectorAll(".audio, .post, .comment");
So you have to do:
const audio = document.querySelector("#audio");
const posts = document.querySelectorAll(".post");
const comments = document.querySelectorAll(".comment");
Can you see how repetitive that is and how it will make it a bit messy to maintain your codebase at scale?
See, you can do the same using $select()
like below with ease:
Solution
const [audio, posts, comments] = $select("#audio, .post, .comment");
Difficulties in debugging DOM selections:
Using document.querySelector()
tends to create more surface area for bugs to hide compared to $select()
because of its support for DOM destructuring and multiple selections.
const audio = document.querySelector("#audio");
const posts = document.querySelectorAll(".post");
const comments = document.querySelectorAll(".comment");
// OR
const [audio, posts, comments] = $select("#audio, .post, .comment");
$select()
reduces the number of lines of code to write to select elements and so reduces the surface area for bugs to hide. That means bugs are more likely to be discovered comparatively faster while using $select()
.
Ability to use all array methods.
Elements selected with querySelector
can only work with forEach
but not map()
, filter()
and co.
$select()
works with all array methods by default unlike document.querySelectorAll()
which requires some workarounds that may lead to unnecessary repetition and complexity at scale.
Maintainability
Maintainability is always revolving around ease of use, brevity and consistency. Any codebase that is concise, consistent or easy to use tends to be maintainable. It is messy to maintain repetitive, and verbose code because you have more surface area to look at especially while fixing a bug or building a feature.
Shipping Less JavaScript
It is a rule of thumb to ship less JavaScript where possible and $select()
makes it feasible while dealing with DOM selection. $select()
is preferable to document.querySelector()
and document.querySelectorAll()
at scale because it is more concise and less repetitive. The more elements you select, the less you repeat selection with $select()
.
Appending or prepending array of elements.
You can’t append an array of elements generated by $select()
to another element like element.append(arrayGeneratedBy$Select)
because the DOM expects NodeList.
Still, you can tell $select()
to disable all of its superpowers by passing false as a second parameter to it.
//superpowers are on by default but you can pass false to off it.
$select('.post', offSuperpowers);
$select('.post', false);
Now, it will return a normal DOM NodeList[]
that is appendable and prependable.
$select() can do that
You maybe curious if $select()
can do everything document.querySelect()
or document.querySelectorAll()
can do. Yes! It can do whatever they do. $select()
can do it all. It can use tag
or css
selectors and do every other things query.querySelector()
can do.
Is document.querySelector() any better?
It is possible to claim that querySelector() or querySelectorAll()
is faster than $select()
with about one millisecond on average but $select()
wins it back with interests at scale.
You still need to learn to use querySelector because understanding how to use it gives you a chance to build something useful on it just like $select(). I am able to build $select() because I truly understand how it works.
I have made a tutorial on it. Check it out below: JavaScript DOM manipulation
Why I won’t use querySelector ever again
By supporting DOM destructuring and enabling array-based selections, $select() proves to be a valuable addition to my toolkit. It not only enhances the readability of my code but also minimizes the surface area for bugs, making debugging a more straightforward process.
In the pursuit of maintainability, brevity, and consistency, $select() emerges as a compelling choice for DOM selection, showing a step forward in the evolution of JavaScript development.
As we continue to adapt to the evolving JavaScript ecosystem, embracing tools like $select()
ensures that we keep making our code more concise, readable, and maintainable.