Is there a way to manipulate the DOM without relying on a library like jQuery?

My usual go-to method for manipulating the DOM involves jQuery, like this:

var mything = $("#mything");
mything.on("click", function() {
    mything.addClass("red");
    mything.html("I have sinned.");
});

Now I am looking to achieve the same result using Vanilla JavaScript. Is there a way to accomplish this? If so, how can it be done?

Attention: This question aims to serve as a comprehensive guide on Vanilla JavaScript DOM manipulation.

Answer №1

When working with the Document Object Model using Vanilla JS, you will directly access the Document and Nodes. A document consists of Elements, specifically HTMLElements and SVGElements which are both considered as Nodes. An Element can also contain Text.

Finding HTML Elements

You can retrieve the first element that matches a CSS selector using mynode.querySelector(), and find all elements that match the selector by using myNode.querySelectorAll(). In most cases, myNode will be the Document, allowing you to locate anything within the entire document that matches the selector. However, when myNode is an element, you can only search through its descendants.

document.querySelectorAll('p:hover'); // Returns a NodeList of hovered paragraphs

This functionality is similar to jQuery('p:hover').

There are specialized methods such as:

These methods have self-explanatory names. Note that .getElementBy... returns a single element while .getElementsBy... (plural elements) returns a NodeList, which functions like an array of nodes but does not have typical array methods.

Check out: What's the best way to loop through a set of elements in JavaScript?

Each element may also possess:

As well as NodeLists of:

This methodology allows for traversal of the DOM structure.

For instance, to find the last child of the initial paragraph element in the parent of #clickme:

document.getElementById('clickme').addEventListener('click', function() {
  console.log(this.parentNode.getElementsByTagName('p')[0].lastChild);
});
<div>
  <blockquote>This is a really great quote.</blockquote>
  <p>This is a <em>really</em> interesting paragraph. <span>this will be selected</span></p>
  <p>In fact, here's another!</p>
  <button id="clickme">Click me!</button>
</div>

...you would identify its parentNode, use getElementsByTagName on this to exclusively target paragraph descendants, select the first one amongst these, and then acquire its lastChild.

To obtain the text contained within it, extract its text node (the initial child) and utilize text.wholeText.

Creating & Deleting Elements

An element can be generated with

document.createElement('aTagName')
or duplicated from another via
newElement = myElement.cloneNode()
. When utilizing cloneNode, input true as the initial argument to also copy its descendants. Avoid cloning elements with an ID since this results in two identical IDs within the same document.

The new element (or an existing one) can then be appended to a parent element using parent.appendChild(newElement) or positioned after another element with

parent.insertBefore(newElement, referenceElement)
. While there isn't a native insertAfter method, one can be created:

HTMLElement.prototype.insertAfter = function(newEl, refEl) {
  if (refEl.nextSibling) refEl.parentNode.insertBefore(newEl, refEl.nextSibling);
  else refEl.parentNode.appendChild(newEl);
};

A node can be removed using parent.removeChild() or replaced with parent.replaceChild(newChild) or simply removed instantly with mynode.remove().

function poof() {
  this.remove();
}
var elements = document.getElementsByClassName('poof');
for (var i = 0; i < elements.length; i++) {
  elements[i].addEventListener('click', poof);
}
<span class="poof">hi,</span>
<span class="poof">click</span>
<span class="poof">to</span>
<span class="poof">delete</span>
<span class="poof">me;</span>
<span class="poof">it</span>
<span class="poof">was</span>
<span class="poof">fun</span>
<span class="poof">being</span>
<span class="poof">a</span>
<span class="poof">span</span>

Classes and Styling

By "and styling," we are referring solely to classes. Styling pertains to CSS. You can apply CSS styles exclusively to elements with added classes through JavaScript.1

Elements in HTML have a classList property, which represents a space-separated property known as class. Within classList, you can add(), remove(), and toggle() classes, verify whether it contains() a certain class, etc.

document.getElementById('clickme').addEventListener('click', function() {
  document.getElementById('colors').classList.toggle('green');
});
.green { color: green }
<div id="colors">hello!</div>
<button id="clickme">Click me!</button>

Attributes

Elements with specific attributes can be selected utilizing querySelector and querySelectorAll. Most attributes already exist as properties of the element currently being manipulated. For example:

myDiv.hidden = true; // Conceals element visually and from screenreaders

If some attributes aren't readily accessible, they can still be obtained using getAttributeNode, setAttributeNode, and removeAttributeNode. AttributeNodes encompass ownerElements and values.

"data-*" attributes can be accessed using myelement.dataset. As an illustration, mydiv.dataset.pie = 'yummy' appends data-pie="yummy" to the div.

Events

Event handling adds complexity. Attaching an event (akin to jQuery('selector').on) is relatively straightforward:

myElement.addEventListener('event-name', afunction);

(Other objects implement this method too – e.g., window)

Events can also be detached:

myelement.removeEventListener('event-name', afunction);

Refer to: removeEventListener

A list of events can be found here.

The function linked to the addEventListener call receives the occurring event as an argument and possesses a this tied to the element where the event listener is bound.

However, events entail more intricacy - a trivial action like clicking a button might trigger multiple event listeners across various elements for diverse events.

– Browser Input Events: Can We Do Better Than The Click? by Smashing Magazine

Additional read: What is event bubbling and capturing?

1 If style modifications via JavaScript are necessary, utilize

myElement.style.styleProperty = 'value'
to modify the inline style attribute.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Want to learn how to display a description below a photo when you hover over it in a photo gallery?

I am currently creating a basic photo gallery where hovering over a thumbnail displays an enlarged photo below it. My goal is to also have text displayed inside a white text box when hovering over each thumbnail, with unique descriptions for each. I need ...

Deleting a file in Express.js after it has been downloaded from the local file system

I'm working on an Express handler that is designed to download a file after detecting a valid file path in the directory entries. The handler includes a command-line option to delete the file after it has been successfully downloaded: res.downloa ...

What could be the reason for PassportJS in Node failing to clear the session upon logout?

I am encountering an issue with my system not successfully logging out using PassportJS. The logout route appears to be triggered, but the session is not being removed as intended. I would like it to return a 401 error if the user is not logged in on a spe ...

Sending a POST request to a Flask server using Stripe and AJAX

I am attempting to implement a function that triggers an ajax request when a stripe form is submitted. However, using the .submit() method doesn't seem to be working as expected. Here is my current code: HTML <form action="/download_data" method= ...

Turn off the ability to click on images, but allow users to access the right

https://i.stack.imgur.com/jriaP.png Example image sourced from reddit.com Illustration represents the desired effect using CSS and possibly JS. In essence: I aim to make an image on a website unclickable to its imageURL There should be a context menu ...

Quick way to specify type for Observable in Typescript

Exploring Shortcut Declarations When working with TypeScript, I often take a shortcut when declaring object shapes. Instead of creating an interface first and then specifying that the object conforms to that type, I simply do: object: { fizz: boolean, buz ...

What is the best way to avoid multiple triggers of an event listener in a Vue Js Component?

When I use an event listener to call a specific function, it behaves strangely. Here is the code snippet: mounted() { window.addEventListener("message", this.call); }, methods: { call(e){ if (e.data === "test"){ ...

Rearranging anchor tag order with the power of JQuery

Imagine I have five anchor tags <a id = "A" class = "Home">Home</a> <a id = "B" class = "Maps">Maps</a> <a id = "C" class = "Plans">Plans</a> <a id = "D" class = "Community">Community</a> <a id = "E" clas ...

What steps can be taken to ensure that the popover div remains visible when clicking inside it in a "dismissible popover" using Twitter Bootstrap with the data-trigger attribute set to "

I am struggling with a dismissible popover that contains a text box. When I click inside the text box to type, it disappears due to the "data-trigger="focus". Is there a way for the div not to disappear when clicked inside intelligently? Here is the releva ...

Prevent drag and drop functionality in QtWebkit

As I work on creating an HTML GUI for my application using Qt's WebKit, everything is going smoothly with one minor issue. I am trying to prevent users from dragging and dropping images from the GUI itself. While I have successfully disabled text sele ...

When the Popover appears in ShadCN, the input field unexpectedly takes focus

This unique component incorporates both Popover and Input functionality from shadcn. An issue I have encountered is that when I click on the Input to trigger the Popover, the Input loses focus and the cursor moves away from it. Expected outcome: Upon c ...

What steps should I take to ensure axios is returning the appropriate buffer type?

Upon initially posting this question, I was completely lost on where to even begin or how to appropriately title it. With the assistance of multiple comments, I enhanced the data provided and finally settled on the current question title - a big thank you ...

The import 'react-router' does not include an export called 'browserHistory'. This issue is coming from the /src/App.js file

I've recently started diving into the routing section of learning react, but I'm a bit puzzled by the error message I encountered. Error: Failed to compile ./src/App.js 31:19-33 'react-router' does not contain an export named 'bro ...

Finding the index of a column based on a continuous sequence of values can be achieved by following these

Consider this sequence of numbers representing components on a page: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 Every set of 3 numbers makes up a page, with indexing restarting for each new page. Essentially, it follo ...

Restricting user access to a route based on its type to enhance security and control

Currently, I have a React, Redux, and Next.js app up and running. Within my redux store, there is a user object that contains an attribute called "type". Each type of user has its own set of "routes" they are allowed to access. I am looking for the most e ...

Using Vue components or elements within the v-html directive allows for dynamic rendering

One of the challenges I'm facing involves handling data from a blog post, specifically the user-submitted text stored in post.text. Similar to Twitter, users can mention other users using syntax like I am tagging @user1 in this post. My goal is to aut ...

SSR not working properly in Nuxt 3

Currently facing an issue where I am unable to access my private environment variables. I understand that I can only retrieve them when my page is server-side rendered (SSR). Strangely, even though I have never disabled SSR, when I log console.log(process. ...

Attempting to establish a connection with a MySQL database through the utilization of Node.js in combination with the mysql javascript client

Recently, I've been facing a challenge connecting to a MySQL database from my electron app: <script> var mysql = require('mysql'); var connection = mysql.createConnection({ host : '*********', ...

"Generating a unique, random HEX color using JavaScript from an array

Currently, I am attempting to create a random border color within a div using specific hex codes that have already been determined, but I am encountering some difficulties. Does anyone have any suggestions on how to achieve this? I am still learning JavaS ...

Securing routes with passport.js in a MEAN Stack setting

I am facing an issue with securing individual routes in my admin panel using passport.js. The user signup functionality is working fine, and I am able to login successfully. However, the req.isAuthenticated() function always returns false, preventing me fr ...