When working with the Document Object Model using Vanilla JS, you will directly access the Document
and Node
s. A document consists of Element
s, specifically HTMLElement
s and SVGElement
s which are both considered as Node
s. 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 NodeList
s 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.