When manipulating the Document Object Model with Vanilla JS, you will be directly be accessing the Document and Nodes. A document contains Elements, particularly HTMLElements and SVGElements which are both Node
s. An Element
may contain Text too.
Finding Elements
You can get the first element which matches a CSS selector with mynode.querySelector(), and all elements that match the selector with myNode.querySelectorAll(). Most of the time myNode
will be Document
, so you can get anything in the document which matches the selector – however, you can look through only a node's descendants when myNode
is a an element.
document.querySelectorAll('p:hover'); // Returns a NodeList of hovered paragraphs
This is similar to jQuery('p:hover')
.
There are also more specialized methods like:
- myNode.getElementById()
- myNode.getElementsByTagName()
- myNode.getElementsByClassName()
- myNode.getElementsByName()
Which have self-explanatory names. Notice that .getElementBy...
returns a single element while .getElementsBy...
(plural elements) returns a NodeList
, which is essentially an array of nodes, but it doesn't have the standard array methods.
See also: What's the best way to loop through a set of elements in JavaScript?
Each element may also have a:
- parentNode
- previousSibling
- previousElementSibling (excludes text nodes)
- nextSibling
- nextElementSibling (excludes text nodes)
- firstChild
- firstElementChild (excludes text nodes)
- lastChild
- lastElementChild (excludes text nodes)
- childElementCount (same as
children.length
)
And NodeList
s of:
- childNodes
- children (excludes text nodes)
In this way, we can traverse the DOM.
For example, to get the last child of the first paragraph element in the parent of #clickme
here:
document.getElementById('clickme').addEventListener('click', function() {
console.log(this.parentNode.getElementsByTagName('p')[0].lastChild);
});
This is a really great quote.
This is a really interesting paragraph. this will be selected
In fact, here's another!
...you find its parentNode
, use getElementsByTagName
on that to only get paragraph descendants, take the first one of those, and get its lastChild
.
To get the text contained in it, you could get its text node (its first child) then use text.wholeText
.
Creating & Deleting
You can create an element with document.createElement('aTagName')
or clone another one with newElement = myElement.cloneNode()
. Pass cloneNode true
as it's first argument to also duplicate its descendants. Don't clone elements with an ID because it will cause 2 elements with the same ID to appear in the same document.
You can then append the new element (or an existing one) to a parent element using parent.appendChild(newElement) or append it after another element with parent.insertBefore(newElement, referenceElement). An insertAfter
method doesn't exist, but it 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 with parent.removeChild() or replaced with parent.replaceChild(newChild) or just removed inline 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);
}
hi,
click
to
delete
me;
it
was
fun
being
a
span
Classes and styles
By "and styles," I mean just classes. Styles are for CSS. You can apply CSS styles only to elements who have had a class added with JavaScript.1
Elements in HTML have a classList property which is a DOMTokenList representing a space-separated property, in this case class
. You can .add()
, .remove()
, and .toggle()
classes in the classList or check if it .contains()
a class.
document.getElementById('clickme').addEventListener('click', function() {
document.getElementById('colors').classList.toggle('green');
});
.green { color: green }
hello!
Attributes
Elements with certain attributes can be selected with querySelector
and querySelectorAll
. Most attributes are properties of the element you're working with already. For example:
myDiv.hidden = true; // Hides element from view and from screenreaders
But if they're not, any attribute can be accessed with getAttributeNode, setAttributeNode, and removeAttributeNode. AttributeNodes have ownerElements and values.
"data-*" attributes can be accessed with myelement.dataset
. For example, mydiv.dataset.pie = 'yummy'
would add data-pie="yummy"
to the div.
Events
Events are slightly more complicated. Binding one (like jQuery('selector').on
) is pretty easy:
myElement.addEventListener('event-name', afunction);
(Other objects also have this method – for example, window
)
Events can also be removed:
myelement.removeEventListener('event-name', afunction);
See: removeEventListener
An event list can be found here.
The function passed to the addEventListener
will be passed an argument of the event occurring and have a this
of the element the event listener is bound to.
However, events aren't this simple: something as trivial as clicking on a button may fire many event listeners on different elements and for different events.
– Browser Input Events: Can We Do Better Than The Click? by Smashing Magazine
See also: What is event bubbling and capturing?
1 If you really need to modify a style with JS, use myElement.style.styleProperty = 'value'
to change the inline style attribute.