You don’t need a Selector Engine since the querySelector() and querySelectorAll() methods are available in the ECMAScript Standard. What happened several years ago, which means that 4.0, 3.5, 3.2, 10.0 and even 8.0 does already support this functions! Okay the last one is MAY a bit tricky, because 9.0 was the first version who supported also CSS 3 selectors. (Which are important… specially for this article!).

The Past: How to get Elements

But before CSS 3 enlights our way, let’s examine how Stone Age Programmers tried to select DOM Elements – long before the fire was invented. Overall they had even four* three methods to select one (or more) DOM Elements. Seriously: The old methods are still supported by all browsers and also still usable, when you just want to select something with ease.

getElementById("your-id")
Just select a single DOM Element, with the respective ID. Returns NULL if no Element could be found!
getElementsByClassName("class-name")
This method selects all DOM Elements with the respective class name and returns this set as HTMLCollection. This method also returns an HTMLCollection object, when no element with the passed class name could be found (Case Sensitive!).
getElementsByTagName("span")
This method selects all DOM Elements with the respective tag name and returns this set as HTMLCollection. This method also returns an HTMLCollection object, when no element with the passed tag name could be found (Case Insensitive!).

* Because nobody used getElementsByTagNameNS()

 

The Future: How to query Elements

Today we don’t want to just “get” elements, we want to query one. Therefore almost the complete CSS 3 Selector Repertoire is available for us. So while the above 3 functions only supports some simple pattern, we can now use complex ones.

A really simple example would be the following, which already combines all 3 above:

// In JavaScript
document.querySelector("span#unique-id.my-class-name");

// In jQuery
jQuery("span#unique-id.my-class-name");

Okay this example is MAY a bit superfluous, because a #unique-id MUST be unique at all, so theoretically we don’t need a tag name. The class name CAN be useful, if a further script change this according to any action. In this case we should also assume, that this method returns NULL. However, it just should illustrate how it CAN look like.

And if you look closer you may notice, that the jQuery method is smaller (it would be even smaller by using just the $-sign). This Problem can also be fixed with ease, by writing a small function like this one below. The following function allows also a second parameter, called context, which is “the parent element” where the selector should be executed.

var select = function(selector, context){
    return (context || document).querySelectorAll(selector);
};

// Now it fits!
select("span#unique-id.my-class-name");
jQuery("span#unique-id.my-class-name");

This is just an example, you can adapt this to your needs.

Vanilla vs jQuery

With this method we can query tag names, class names, unique IDs and even attributes like [target] or [data-attribute="value"]. There are also some Attribute compare function, which are listed and desribed on w3schools.com. But jQuery still has many special Selectors, how can JavaScript keep up with these?

I went through the jQuery Selector list and could only found 5 Strings were I couldn’t found a Vanilla JS / CSS 3 working solution! Below you will find this huge list, which shows all special jQuery Selector strings with a working Vanilla JavaScript alternative.

Just Shortcodes

The following jQuery selectors are just “Shortcodes”.

Show all Shortcode Selectors
jQuery(":button")
select("button, input[type=button]")
select("button, input[type=submit], input[type=reset], input[type=button]")
The jQuery selector just selects “button, input[type=button]” elements, like the second plain-vanilla line. You can also extend this (as shown in the third line) and query each available button!

jQuery(":checkbox")
select("input[type=checkbox]")
The “:checkbox” selector is just a shortcode for input checkboxes.

jQuery(":checked")
select("input:checked")
The “:checked” selector is just a shortcode for checked Input Radio and Checkboxes. The same Shortcode is also available in the CSS 3 Standard but will also select “selected” options. To prevent this, we need to clarify our selector by adding input in front of it.

jQuery(":disabled")
select(":disabled")
The “:disabled” selector is just a shortcode for disabled form fields.

jQuery(":enabled")
select(":enabled")
The “:enabled” selector is just a shortcode for non-disabled form fields.

jQuery(":file")
select("input[type=file]")
The “:file” selector is just a shortcode for input file fields.

jQuery(":header")
select("h1, h2, h3, h4, h5, h6")
The “:header” selector is just a shortcode for the main h[0-9] HTML elements.

jQuery(":image")
select("input[type=image]")
The “:image” selector is just a shortcode for input image fields.

jQuery(":input")
select("input, textarea, select, button")
The “:input” selector is just a shortcode for all available input fields.

jQuery(":password")
select("input[type=password]")
The “:password” selector is just a shortcode for input password fields.

jQuery(":radio")
select("input[type=radio]")
The “:radio” selector is just a shortcode for input radio fields.

jQuery(":reset")
select("input[type=reset]")
The “:reset” selector is just a shortcode for input reset buttons.

jQuery(":selected")
select("option:checked")
The “:selected” selector is just a shortcode for selected options. The CSS 3 Standard uses “:checked” for input and option fields, so we need to clarify this by adding option in front of our selector.

jQuery(":submit")
select("input[type=submit]")
The “:submit” selector is just a shortcode for input submit buttons.

jQuery(":text")
select("input[type=text]")
The “:text” selector is just a shortcode for input text fields.

Special Selectors

The following Selectors are really special, either CSS 3 or jQuery magic.

Show all Special Selectors
jQuery("element:empty")
select("element:empty")
The “:empty” selector grabs each element, which has no children nor a text node inside. This is also available in plain vanilla JavaScript / CSS 3.

jQuery("element:eq(number)")
select("element")[number]
The “:eq(n)” selector returns the n-th element in the list. You can easily achieve the same in vanilla JavaScript, by just using the [n] brackets after the function!

jQuery("element:even")
select("element:nth-child(even)")
The “:even” selector returns each “even” item within the list. CSS 3 supports something similiar by using :nth-child(even)!

jQuery("element:first-child") and jQuery("element:last-child")
select("element:first-child") and select("element:last-child")
The “:first-child” and “:last-child” selectors selects every element that is the first (or last) child of its parent. Both are standardized by CSS 2 and of course also available in vanilla JavaScript!

jQuery("element:first-of-type") and jQuery("element:last-of-type")
select("element:first-of-type") and select("element:last-of-type")
The “:first-of-type” and “:last-of-type” selectors selects every element that is the first (or last) element of its parent. Both are standardized by CSS 3 and of course also available in vanilla JavaScript!

jQuery("element:first") and jQuery("element:last")
select("element")[0] and select("element")[length-1]
The “:first” and “:last” pseudo-classname selectors just returns the really “first” / “last” element of the list. You can achieve the same in the same way as “:eq(x)”!

jQuery("element:gt(number)")
select("element:nth-child(1n+number)")
The “:gt()” selector selects all elements at an index greater than the passed number. The same can also be achieved in vanilla JavaScript by using “:nth-child(1n+number)”. Please Note: This may doesn’t work in all modern / CSS 3 compliant browsers!

jQuery("element:lang(language)")
select("element:lang(language)")
The “:lang()” selector selects every element with a lang attribute equal to language. This has been standardized by CSS 3 and is of course also available in vanilla JavaScript!

jQuery("element:lt(number)")
select("element:not(:nth-child(1n+number)"))
The “:lt()” selector selects all elements at an index lower than the passed number. The same can also be achieved in vanilla JavaScript by using “:not(:nth-child(1n+number))”. Please Note: This may doesn’t work in all modern / CSS 3 compliant browsers!

jQuery("element:not()")
select("element:not()")
The “not()” selector selects all elements that don’t match the given selector. This has been standardized by CSS 3 and is of course also available in vanilla JavaScript! Please Note: The jQuery version may work differently compared to the vanilla JavaScript version!

jQuery("element:nth-child(number)")
select("element:nth-child(number)")
The “:nth-child(n)” selector selects every element that is the n-th child of its parent. This has been standardized by CSS 3 and is of course also available in vanilla JavaScript!

jQuery("element:nth-last-child(number)")
select("element:nth-last-child(number)")
The “:nth-child(n)” selector selects every element that is the n-th child of its parent, counting from the last child. This has been standardized by CSS 3 and is of course also available in vanilla JavaScript!

jQuery("element:nth-last-of-type(number)")
select("element:nth-last-of-type(number)")
The “:nth-child(n)” selector selects every element that is the n-th element of its parent, counting from the last child. This has been standardized by CSS 3 and is of course also available in vanilla JavaScript!

jQuery("element:nth-of-type(number)")
select("element:nth-of-typenumber)")
The “:nth-child(n)” selector selects every element that is the n-th element of its parent. This has been standardized by CSS 3 and is of course also available in vanilla JavaScript!

jQuery("element:odd")
select("element:nth-child(odd)")
The “:odd” selector returns each “odd” item within the list. CSS 3 supports something similiar by using :nth-child(odd)!

jQuery("element:only-child")
select("element:only-child")
The “:nth-child(n)” selector selects every element that is the only child of its parent. This has been standardized by CSS 3 and is of course also available in vanilla JavaScript!

jQuery("element:only-of-type")
select("element:only-of-type")
The “:nth-child(n)” selector selects every element that is the only element of its parent. This has been standardized by CSS 3 and is of course also available in vanilla JavaScript!

jQuery("element:parent")
select("element:not(:empty)")
The “:parent” selector selects all elements that have at least one child node (either an element or text). So this means elements which aren’t empty, so we can use “:not()” no negate the “:empty” selector. Please Note: This may doesn’t work in all modern / CSS 3 compliant browsers
jQuery(":root")
select(":root")
The “:root” selector just selects the document’s root element and is also available in CSS 3 and, of course, in vanilla JavaScript.

jQuery(":target")
select(":target")
select(window.location.hash)
The “:target” selector selects the target element indicated by the fragment identifier of the document’s URI. The same selector is also defined in CSS 3 (and also available in vanilla JavaScript), but can also be achieved with the third line.

Unsupported Selectors

The following 5 jQuery Selectors are left, where I couldn’t found a working solution!

Hide all Usupported Selectors
jQuery(":animated")
The “:animated” selector selects all elements that are in the progress of an animation at the time the selector is run.
jQuery(":contains(text)")
The “:contains()” selector selects all elements that contains the specified text.
jQuery(":has(selector)")
The “:has()” selector selects elements which contain at least one element that matches the specified selector.
jQuery(":hidden")
The “:hidden” selector selects all elements that are hidden.
jQuery(":visible")
The “:visible” selector selects all elements that are visible.

Why I don’t like Selector Engines

You may think Cool, but why should I use vanilla if jQuery is smarter and smaller?. That’s correct: jQuery Selector strings are way shorter, but the execution time is just heavy compared to Vanilla JavaScript. The jQuery documentation itself often preaches caution when using special selectors, or recommends to roughly select the elements in advance.

Please don’t get me wrong, this whole DOM and function libraries arn’t bad (ok rather the must of them) and specially jQuery was a really good library, back in 2010. Nowadays, where anyone who uses the Internet Explorer < 11 does it just out of self-hatred and where JavaScript envolves, you don't need jQuery at all. And this Just Vanilla blog post series here on this website should prove that to you!