Replacing jQuery with Vanilla JavaScript
Tags: javascript, jquery, refactor, frontend
Published: 2021-11-11 18:55:13

For many years, it seemed as if jQuery had become synonymous with JavaScript. Since its introduction in 2006, jQuery caused a revolution in front-end scripting.

**jQuery** is still a useful library. With broad browser support of ES6, now is probably a good time to move away from jQuery.

One of the reference sites I like (because of the side-by-side replacement options) is [You Might Not Need jQuery](https://youmightnotneedjquery.com/).

## Index

1. [Document Ready](#document-ready)
2. [Selecting Elements](#selecting-elements)
3. [Working with Classes](#working-with-classes)
4. [Working with Events](#working-with-events)
5. [Network Requests](#network-requests)
6. [Updating the DOM](#updating-the-dom)

## Document Ready

To wait for the DOM to fully load, jQuery used `$(document).ready()` or the common short-hand `$()` in jQuery. This can easily be constructed in a similar function to replace it with by listening to `DOMContentLoaded`.

```javascript
// With jQuery
$(document).ready(function() { 
  /* Do things after DOM has fully loaded */
});

// Without jQuery
const onReady = (callback) =>{
  if (document.readyState!='loading') callback();
  else if (document.addEventListener) document.addEventListener('DOMContentLoaded', callback);
  else document.attachEvent('onreadystatechange', function() {
    if (document.readyState=='complete') callback();
  });
};

ready(() => { 
  /* Do things after DOM has fully loaded */ 
});
```

## Selecting Elements

Selecting one or several DOM elements to do something with is one of the most basic elements of jQuery. The equivalent to `$()` or `jQuery()` in JavaScript is `querySelector()` or `querySelectorAll()`, which can be called with a CSS selector.

```javascript
// jQuery, select all instances of .item
$('.item');

// Instead, select the first instance of .item
document.querySelector('.item');

// ... or, select all instances of .item  
document.querySelectorAll('.item');
```

### Acting on All Elements in a Selection

`querySelectorAll()` returns a NodeList containing all of the elements matching the query. JavaScript needs to iterate over the NodeList of elements using `NodeList.forEach()` in vanilla JavaScript.

```javascript
// With jQuery
$('.item').hide();

// Without jQuery
document.querySelectorAll('.item').forEach(item => {
  item.style.display = 'none';
});
```

### Finding an Element within Another

A common jQuery pattern is to select an element within another element using `.find()`. The same effect can be achieved by scoping the selection to an element’s children, by calling `querySelector` or `querySelectorAll` on an element.

```javascript
// With jQuery
const container = $('.wrapper');
container.find('.item');

// Without jQuery
const container = document.querySelector('.wrapper');
container.querySelector('.item');
```

### Traversing the DOM Tree

To traverse the DOM, select a sibling or a parent element relative to another element through `nextElementSibling`, `previousElementSibling` and `parentElement`.

```javascript
// With jQuery
$('.item').next();
$('.item').prev();
$('.item').parent();

// Without jQuery
const item = document.querySelector('.item');
item.nextElementSibling;
item.previousElementSibling;
item.parentElement;
```

### Styling Elements

When calling `.css()` on an element to change its inline CSS with jQuery, use `.style` in JavaScript and assign values to its different properties to achieve the same effect.

```javascript
// With jQuery
$('.item').css('color', '#000');

// Without jQuery
document.querySelector('item').style.color = '#000';
```

With jQuery, pass an object with key-value pairs to style many properties at once. In JavaScript, set the values one at a time, or set the entire style string.

```javascript
// With jQuery
$('.item').css({
  'color': '#000',
  'background-color': 'red'
});

// Without jQuery
const item = document.querySelector('.item');
item.style.color = '#000';
item.style.backgroundColor = 'red';

// Set all styles at once (and override any existing styles)
item.style.cssText = 'color: #000; background-color: red';
```

### Creating Elements

To dynamically create an element in JavaScript and add it to the DOM, can call `createElement()` and pass it a tag name to indicate what element to create.

```javascript
// Create a div and span
$('<div/>');
$('<span/>');

// Create a div and a span
document.createElement('div');
document.createElement('span');
```

To add some content to those elements, simply set the `textContent` property, or create a text node with `createTextNode` and append it to the element.

```javascript
const element = document.createElement('div');
element.textContent = 'Text';

const text = document.createTextNode('Text');
element.appendChild(text);
```

## Working with Classes

The code can easily access and work with classes through the `classList` property to `toggle`, `replace`, `add`, and `remove` classes.

```javascript
// With jQuery
$('.item').addClass('focus');
$('.item').removeClass('focus');
$('.item').toggleClass('focus');

// Without jQuery
const item = document.querySelector('.item');
item.classList.add('focus');
item.classList.remove('focus');
item.classList.toggle('focus');
```

To remove or add multiple classes, just pass multiple arguments to `.add()` and `.remove()`.

```javascript
// Add focus and highlighted classes, then remove
const item = document.querySelector('.item');
item.classList.add('focus', 'highlighted');
item.classList.remove('focus', 'highlighted');
```

When toggling two classes that are mutually exclusive, access the `classList` property and call `.replace()` to replace one class with another.

```javascript
// Remove the focus class and add blurred
document.querySelector('.item').classList.replace('focus', 'blurred');
```

### Checking if an Element has a Class

To run a function if an element has a certain class, replace jQuery’s `.hasClass()` with `.classList.contains()`.

```javascript
// With jQuery
if ($('.item').hasClass('focus')) {
  // Do something...
}

// Without jQuery
if (document.querySelector('.item').classList.contains('focus')) {
  // Do something...
}
```

## Working with Events

There are many ways to listen to events in jQuery, but whether using `.on()`, `.bind()`, `.live` or `.click()`, make do with the JavaScript equivalent `.addEventListener`.

```javascript
// With jQuery
$('.button').click(function(e) {
  /* handle click event */
});
$('.button').mouseenter(function(e) {
  /* handle click event */
});
$(document).keyup(function(e) {
  /* handle key up event */
});

// Without jQuery
document.querySelector('.button').addEventListener('click', (e) => {
  /* ... */
});
document.querySelector('.button').addEventListener('mouseenter', (e) => {
  /* ... */
});
document.addEventListener('keyup', (e) => {
  /* ... */
});
```

### Listening for Dynamically Added Elements

jQuery’s `.on()` method works with *live* event handlers that listen to events on objects that get dynamically added to the DOM. To accomplish something similar without jQuery, attach the event handler on an element as it is added to the DOM.

```javascript
// With jQuery
$('.search-container').on('click', '.search-result', handleClick);

// Without jQuery
const searchElement = document.createElement('div');
document.querySelector('.search-container').appendChild(searchElement);
searchElement.addEventListener('click', handleClick);
```

### Triggering and Creating Events

The equivalent to manually triggering events with `trigger()` can be achieved by calling `dispatchEvent()`. The `dispatchEvent()` method can be invoked on any element, and takes an Event as the first argument.

```javascript
// With jQuery
$(document).trigger('myEvent');
$('.item').trigger('myEvent');

// Without jQuery
document.dispatchEvent(new Event('myEvent'));
document.querySelector('.item').dispatchEvent(new Event('myEvent'));
```

### `hide()` and `show()`

The `.hide()` and `.show()` functions are convenience methods that are equivalent to accessing the `.style` property and setting `display: none;` and `display: block;`.

```javascript
// With jQuery
$('.item').hide();
$('.item').show();

// Without jQuery
document.querySelector('.item').style.display = 'none';
document.querySelector('.item').style.display = 'block';
```

## Network Requests

`fetch()` creates a network request in a similar fashion to jQuery’s `ajax()` and `get()` methods. `fetch()` takes a URL as an argument, and returns a Promise that can be used to handle the response.

```javascript
// With jQuery
$.ajax({
    url: 'data.json'
  }).done(function(data) {
    // ...
  }).fail(function() {
    // Handle error
  });

// Without jQuery
fetch('data.json')
  .then(data => {
    // Handle data
  }).catch(error => {
    // Handle error
  });
```

## Updating the DOM

To change the text of an element or to add new elements to the DOM `innerHTML()` comes to mind, but using it may expose the code to cross-site scripting (XSS) attacks. There are some safer alternatives.

To read or update the text of an element, use the `textContent` property of an object to return the current text, or update it ...

```javascript
// With jQuery
$('.button').text('New text');
$('.button').text(); // Returns 'New text'

// Without jQuery
document.querySelector('.button').textContent = 'New text';
document.querySelector('.button').textContent; // Returns 'New text'
```

When constructing a new element and add that element to another element by using the method on the parent `appendChild()` ...

```javascript
// Create div element and append it to .container
$('.container').append($('<div/>'));

// Create a div and append it to .container
const element = document.createElement('div');
document.querySelector('.container').appendChild(element);
```

Put together, here is how to create a div, update its text and class, and add it to the DOM ...

```javascript
const element = document.createElement('div');
element.classList.add('item');
element.textContent = 'Text inside item.';
document.querySelector('.container').appendChild(element);
```

## Summary

**jQuery** caused a revolution in front-end scripting and it is still a useful library. However, with broad browser support of ES6, now is probably a good time to move away from jQuery.

We have covered: Document Ready, Selecting Elements, Working with Classes, Working with Events, Network Requests, and Updating the DOM. These six major categories cover much of what jQuery was used to implement.