querySelectorAll()If you’ve ever created a website, you’ve surely used jQuery.

It’s a lovely JavaScript library that lets you do all sorts of whiz-bang Web 2.0 stuff while shielding you from the underlying plain vanilla JS functions.

But hang on a minute – do you really need jQuery?

The answer is, as usual, complicated… but fascinating!

jQuery Selectors

jQuery is great in that it gives you an easy way to select elements from the DOM tree. For example, you can do:


That will get the DIV with id=my-div and then show it (if it’s hidden).


Now, the reality is that jQuery just takes the native JavaScript function document.querySelectorAll() and wraps it in some added functionality.

But the vast majority of the time, you don’t actually need those added bells and whistles.

So, what can you do with document.querySelectorAll()? Just about everything!

First, it’s a bit tedious to have to type all that out every time, so you could just do something like this:

$ = function(str) {
  return document.querySelectorAll(str);

Ta-DA! You now have a very simple method $ just like jQuery. And that means you can do all sorts of exciting things.

The string you pass into $ is a Selector.

Note carefully that while we’re kind of talking about CSS selectors, not all pseudo classes (like :visited) are supported by querySelectorAll()!!

The returned value is actually a NodeList. NodeLists are actually quasi-arrays of nodes from the DOM tree.

Just be aware that while you can iterate through NodeLists (like with a for or forEach loop), you cannot use normal array functions like pop().

NodeLists are not true arrays.

If no matches are found, then you end up with an empty NodeList, which has .length==0.

So what CAN you do with your new $?


$('*') 			\\ Select all elements on the page
$('div')		\\ Select only DIV elements (or whatever HTML tag you want)
$('.myclass')		\\ Selects all elements with class='myclass'
$('input.myclass')	\\ Selects all INPUT elements with class='myclass'
$('input#firstname')	\\ Select INPUT with id='firstname'

Well, alrighty then! But what about the fancier stuff?

$('div[title]')			\\ Select DIV tag(s) with any title attribute set
$('a[title="New Article"]')	\\ Select A tags where title='New Article'
$('a[href="/docs/pdf"]')	\\ Select A tags with href = given relative URL
$('a[href*="docs"]')		\\ Select A tags with href that contains 'docs'
$('a[href^="#"]')		\\ Select A tags with href that begins with '#'
$('a[href$="pdf"]')		\\ Select A tags with href that ends with 'pdf'
$('div[class~="small"]')	\\ Select DIV tags with class that contains the word 'small'
$('div[title*="cHeEsE" s]')	\\ Select DIV with title containing 'cHeEsE' (case sensitive)
$('div[title*="cHeEsE" i]')	\\ Select DIV with title containing 'cHeEsE' (case INsensitive)
$('div[id|="sh"]')		\\ Select DIVs with id beginning with 'sh-'

YIKES! Since you can select via any attribute of any HTML tag, this allows you to do all kinds of interesting things.

But wait! There’s more!

$('div p')	\\ Select P tags that are inside DIV tags
$('div > p')	\\ Select P tags that are direct children of DIV tags
$('div + p')	\\ Select P tags that are siblings of DIV tags where the P appears immediately after the DIV
$('div ~ p')	\\ Select P tags that are siblings of DIV tags where P appears after the DIV tag
$('div#mydiv a[href$="pdf"]')	\\ Select A tags with href ending in 'pdf' that are inside DIV with id='mydiv'

Hopefully, you begin to get the idea here…

Even though pseudo-selectors such as :visited are not supported by your new $ function, it doesn’t really matter.

Let’s say you want to get the 4th paragraph inside a DIV with id=’mydiv’. Just do this:

$('div#mydiv p')[3]

Since the returned NodeList is a quasi-array, [3] will give you the 4th element [0, 1, 2, 3].

So then you can do stuff like:

var paragraph = $('div#mydiv p')[3];
paragraph.title = 'CHEESE!';
console.log("Content of paragraph =", paragraph.innerHTML);
paragraph.innerHTML = 'This is the new text that will appear inside the P tag!';

Or just change the contents directly:

$('div#mydiv p')[3].innerHTML = 'This is the new text that will appear inside the P tag!';

There are other tricks, as well. In fact, there’s a LOT that document.querySelectorAll() can do for you.

A word of caution…

You can also call querySelectorAll() on something other than document.

From Mozilla’s web site, we read that you can do:

var select = document.querySelector('.select');
var inner = select.querySelectorAll(':scope .outer .inner');

Don’t do this.

Normally, you have to use the :scope pseudomodifier, and it often doesn’t work the way you expect.

There really isn’t any need to do this anyway if you’re creative with your selectors!

Isn’t that kind of complicated?

Not really. You’ve learned to do similarly complicated things with jQuery. You’re just used to it by now.

Still, there’s a reason to use a library to make things easier.

For example, chaining of functions:

$('div#mydiv p').attr('title', 'CHEESE').html('New P content goes here!');

So, there IS a reason to use a library. Just use mine instead!


I’ve already written an article about PikaJS, and you can find PIkaJS on Github.

The big news is that just yesterday, I released PikaJS v2.0!

In addition to v2.0, I will be releasing 4 plugins: Pika Animate, Pika Datepicker, Pika Multiselect, and Pika Hotkeys.

Pika 2.0 is 100% compatible with Pika 1.2, and only 1.9kB larger in size even though it has 20 new methods (for 50 in total).

That means it’s still 7 times smaller than jQuery 3.6.0, much faster, and has all the functionality you could ever want.

Check out PikaJS v2.0 on github!!

Need help? Hire me!
Get Scottie Stuff!