First get access..

Before performing any DOM methods on any HTML element it is necessary that we get first select. Selecting an element for DOM manipulation is just like a key for a car - you can't start the car without the key!

When we access an element we basically fetch it in the form of a JavaScript DOM object on which we can perform methods as we wish. This we will explore in the next HTML DOM Elements chapter.

In this chapter we will begin by introducing you to a lot of ways to select a single element or a bunch of elements, that are dependent on either their attribute values, tag names or parent-child relationships.

Let's begin!

Selecting by Id

The easiest way to access an element in JavaScript is using the getElementById() method, of the document object.

The method simply fetches an element by its id attribute.

The ID of the desired element is passed to the method as a string, which then looks for it and finally returns a reference to it, if it exists.

Let's see a quick example. Consider the following <p> element:

<p id="p1">A paragraph</p>

To select this paragraph, using its id, we can simply write the following:

var ele = document.getElementById("p1");

The expression document.getElementById("p1") will return an element node for the paragraph element shown above, which will consequently be saved in the variable ele.

If you're using Google Chrome, go to the console, write the following statement and then take your mouse over the returned text. You will see the respective element been highlighted.

Once we have an element node, we can do a lot of different things using it.

Just to name one thing: we can retrieve the content of the element by accessing the property innerHTML:

var ele = document.getElementById("p1");

// log the element's content
console.log(ele.innerHTML);
A paragraph
We will explore the innerHTML property, in detail, in the next chapter — JavaScript HTML DOM Elements.

ID's in a web page are supposed to be unique and accordingly, the method getElementById() returns only a single element.

If we have two elements in a web page with similar id's, then the method will only return the first element.

Consider the example below:

<p id="p1">Paragraph 1</p>
<p id="p1">Paragraph 2</p>
var ele = document.getElementById("p1");

console.log(ele.innerHTML);
Paragraph 1

As you can clearly see from the log, the selected element is the first <p> element with id="p1".

Selecting by class

Apart from id, another attribute frequently used to help in selecting elements in JavaScript, is the class attribute. It's also useful in selecting elements in CSS.

To fetch a bunch of elements with a given class, we can use the getElementsByClassName() method.

It takes in the given class name as a string and returns an array-like list of DOM elements that have that class.

To be precise, it returns an HTMLCollection object that carries all the matching element nodes within it.

An HTMLCollection object is a sequential data class, pretty similar to a JavaScript array. Each element node is stored at an index, starting from 0, accessible through bracket notation. The total number of elements can be retrieved via the length property.

Just by reading this we can see that HTMLCollection is very much similar to the Array class — it is indexed, has a length property and individual elements can be accessed using bracket notation.

However, remember that an HTMLCollection object isn't related to the Array class — it doesn't inherit from Array.prototype and therefore has no array methods available.

It's just like an array!

Another things to note here, is that getElementsByClassName() returns a list of all the selected elements. Hence, we have to first refer to an individual element in the list before we can start working with it.

Let's see it all in action!

In the HTML code shown below, we have two <p> elements with a class of p1:

<p class="p1">A .p1 element</p>
<p class="p1">Another .p1 element</p>

To select both these .p1 elements, we can simply write the following statement:

var eleList = document.getElementsByClassName("p1");

The method looks for all elements in the document with a class of p1, puts all the matches in a list and finally returns the list. This list is saved in the variable eleList.

We've changed the name of the variable from ele to eleList to emphasize on the fact that unlike getElementById() which returns the element directly, getElementsByClassName() return a list.

Now if we want to use both the selected elements for further processing, we have to refer to each of them via an index — just like we do with arrays.

For details on how to work with indexes in arrays, consider reading JavaScript Arrays Basics Concepts.

Consider the code below:

var eleList = document.getElementsByClassName("p1");

console.log(eleList[0].innerHTML);
console.log(eleList[1].innerHTML);

eleList[0] refers to the first element in the eleList collection, whereas eleList[1] refers to the second element in the collection.

A .p1 element
Another .p1 element

In this example, since there were only two <p> elements, we managed to refer to each of them directly. However, in general, when the elements are in large numbers, it's common, convenient and efficient to shift this logic under the hood of loops.

Working with an HTMLCollection object in a for loop is extremely easy — thanks to its length property.

Below shown is the rewritten version of the code above, using a for loop:

var eleList = document.getElementsByClassName("p1");

for (var i = 0, len = eleList.length; i < len; i++) {
    console.log(eleList[i].innerHTML);
}
A .p1 element
Another .p1 element

The former way, where we access each element manually, is much useful when we have only one (or sometimes even two) element to deal with. The latter, where we use a loop, is much more useful when we have to process multiple elements.

Notice the 's' in the name getElementsByClassName(). The name implies that the method considers to fetch elements, not just a single element! We have said before — names are indicators of function's purposes!

Write a program that selects all the .hidden elements shown below, and then logs their innerHTML properties one-by-one.

<section class="hidden">Some content</p>

<p>A <span class="hidden">span</span> element</p>

<div class="hidden">Some content</div>
<div>Some more content</div>
var hiddenElems = document.getElementsByClassName("hidden");

for (var i = 0, len = hiddenElems.length; i < len; i++) {
    console.log(hiddenElems[i].innerHTML);
}

Selecting by tag name

So you've got no id or class attributes on your HTML elements and still want to select 'em, based on their tagnames.

Well, it ain't a big deal — just use the getElementsByTagName() method.

It operates exactly like getElementsByClassName(), except for that it searches for elements based on given tag names rather than given class names.

The tag name is provided to the method, once again, as a string, which then returns an HTMLCollection list containing all the fetched elements.

For example, to select all <script> elements, we would call document.getElementsByTagName("script").

Remember that getElementsByTagName() also returns a list, just like getElementsByClassName(). Hence, we have to refer to individual elements via indexes before we can work with them

Consider the markup below:

<p>First paragraph</p>
<p>Second paragraph</p>

<div>A div element</div>

<p>Third paragraph</p>

The following code fetches all the <p> elements shown above and logs each one's innerHTML:

var eleList = document.getElementsByTagName("p");

for (var i = 0, len = eleList.length; i < len; i++) {
    console.log(eleList[i].innerHTML);
}
First paragraph
Second paragraph
Third paragraph
As with both the methods discussed above, the tag name passed to getElementsByTagName(), as an argument, is case-insensitive.

Both, getElementsByTagName("script") and getElementsByTagName("SCRIPT") are identical to one another.

Write a program that selects all the <section> elements shown below, and then logs their innerHTML properties one-by-one.

<h1>Heading 1</h1>
<section>Section 1</section>

<h1>Heading 2</h1>
<section>Section 2</section>
var sectionElems = document.getElementsByTagName("section");

for (var i = 0, len = sectionElems.length; i < len; i++) {
    console.log(sectionElems[i].innerHTML);
}

Mixing these

The beauty of all the three methods we've seen above is that they operate on the document object, as well as on any given element node.

In all the examples above, we've called the methods on the document object, in which case the searching was performed over the whole HTML document.

Now we shall consider these methods on selected element nodes and see how do they behave this time. Well it's nothing new!

When a searching method such as getElementById() is called on an element node ele, searching is performed precisely over that very element.

Consider the HTML below:

<div id="main">
    <p class="small">A paragraph inside</p>
    <p class="small">Another paragraph inside</p>
</div>

<p class="small">A paragraph outside</p>

We have a #main container with two .small elements, in addition to a .small element outside the container.

We'll first select all these three .small elements using the document.getElementsByClassName() method, before moving on to selecting only the two inside #main.

var eleList = document.getElementsByClassName("small");

console.log(eleList.length); // 3

As is clear here, the length of eleList is 3 because document.getElementsByClassName("small") selects all the three .small elements.

Now let's see how to fetch only the two elements inside the #main div.

var main = document.getElementById("main"),
     smallElems = main.getElementsByClassName("small");

console.log(smallElems.length); // 2

Because we need to search for .small elements inside #main, the first step is to select #main. This is done is line 1 and the result is saved inside the variable main.

Now, since searching has to be done within this element, we call getElementsByClassName() on main. The result is an HTMLCollection list holding the two .small elements inside #main. This list is saved in the variable smallElems.

To see what's selected, take a look at the code below. We log each selected element's innerHTML property:

var main = document.getElementById("main"),
smallElems = main.getElementsByClassName("small");

for (var i = 0, len = smallElems.length; i < len; i++) {
    console.log(smallElems[i]);
}
A paragraph inside
Another paragraph inside

As expected, we get the two <p> elements inside the #main container.

Let's play with another example, this time a bit more complicated then the one above.

In the snippet below, we have various .small elements scattered over the HTML markup. The goal is to log the content of all those that are contained within .main elements.

<div class="main">
    <p class="small">Paragraph 1</p>
    <p class="small">Paragraph 2</p>
</div>

<p class="small">Paragraph 3</p>

<div class="main">
    <p class="small">Paragraph 4</p>
    <p class="small">Paragraph 5</p>
</div>

We'll start by getting done with the first concern i.e selecting all .main elements:

var mainElements = document.getElementsByClassName("main");

After this, for each .main element, we'll select all .small elements within it and log their content one-by-one:

var mainElements = document.getElementsByClassName("main");

for (var i = 0, mLen = mainElements.length; i < mLen; i++) {
    // fetch all .small elements inside the current .main element
    var smallElements = mainElements[i].getElementsByClassName("small");

    for (var j = 0, sLen = smallElements.length; j < sLen; j++) {
        console.log(smallElements[j].innerHTML);
    }
}

Notice the nested for loops - the first one works on each selected .main element, whereas the second one works on each selected .small element.

Paragraph 1
Paragraph 2
Paragraph 4
Paragraph 5

Now although, the code above does select the desired elements, you would surely agree that it's way too complex for even simple fetching problems.

Imagine having to select all <b> elements inside all .small elements inside all .main elements. Even saying it out loud sounds gibberish!

A better method is needed here; and indeed there is. In fact, there are two such methods - querySelector() and querySelectorAll(), as we shall see in the next section.

Selector-based fetching

As we have seen just right now, selecting elements in JavaScript can sometimes become quite a challenging task if to be done using one or more of three selection methods we discussed above.

Fortunately, we don't need to worry even a bit - two methods allow us to select elements via the CSS selector syntax.

For more info on the CSS selector syntax, please refer to CSS Selectors.

They are querySelector() and querySelectorAll().

We pass in the CSS selector as a string, and both these methods in turn return the matched element(s).

The querySelector() method selects the first matched element while querySelectorAll() selects all matched elements.

As with getElementsByClassName() and getElementsByTagName(), the method querySelectorAll() also returns a list of the matched elements.

However, this list is NOT an HTMLCollection object. Rather it is a NodeList object.

A NodeList object is very similar to an HTMLCollection object.

As expected, it is also indexed, has a length property and contains elements accessible via bracket notation.

On the outskirts, it operates exactly like an HTMLCollection object, however it has one crucial difference. This we shall explore later in the section below.

Anyways, using these two methods, we can easily and efficiently select elements with extremely complex nestings; which would otherwise take multiple lines of code if done using the methods discussed above.

Let's consider the same example above, this time to be solved in a more elegant way:

<div class="main">
    <p class="small">Paragraph 1</p>
    <p class="small">Paragraph 2</p>
</div>

<p class="small">Paragraph 3</p>

<div class="main">
    <p class="small">Paragraph 4</p>
    <p class="small">Paragraph 5</p>
</div>

We needed to select all .small elements that were within a .main element and log each one's innerHTML.

Following we use the querySelectorAll() method to solve this task:

var eleList = document.querySelectorAll(".main .small");

for (var i = 0, len = eleList.length; i < len; i++) {
    console.log(eleList[i].innerHTML);
}
Paragraph 1
Paragraph 2
Paragraph 4
Paragraph 5

If we use querySelector() rather than querySelectorAll() here, it would return only the first matched element rather than a list.

Consider the code below:

var ele = document.querySelector(".main .small");

console.log(ele.innerHTML);
Paragraph 1
You can use any CSS selectors in these methods like querySelector(".article:last-child").
querySelector(selector) is same as calling querySelectorAll(selector)[0].

Pre-defined DOM collections

Apart from the methods we saw above to select elements, JavaScript comes equipped with a handful of properties on the document object that have some common HTML elements pre-selected.

Below shown is the list of these properties:

  1. document.documentElement selects the <html> element.
  2. document.head selects the <head> element.
  3. document.body selects the <body> element.
  4. document.scripts selects all <script> elements.
  5. document.links selects all the <a> elements.
  6. document.forms selects all the <form> elements.
  7. document.images selects all the <img> elements.

So, in order to select the <body> element, instead of going like:

document.getElementsByTagName("body")[0];

we can simply just write:

document.body

And in this way we can select the <body> element pretty easily.

What will the following expression evaluate to?

document.getElementsByTagName("script")[0] === document.scripts
  • true
  • false

In the coming chapters we'll be, at least, using the first three properties pretty frequently — document.documentElement, document.head, and document.body. So, just make sure you have a good understanding of them.

Relationship-based fetching

In the previous HTML DOM Tree chapter we saw the DOM tree model and how various nodes are linked together via parent-child or sibling relationships.

For instance, <html> is the parent node of <body>, while <body> is the child node of <html>. Similarly, <head> is the sibling of <body> and so on and so forth.

Now, in this chapter, we shall use this relationship to select given elements in a document starting from another given element.

The properties we'll be exploring are parentNode, childNodes, nextSibling, previousSibling and after these children, nextElementSibling and previousElementSibling.

parentNode

The parentNode property of a given element node points to its parent.

If an element does not have a parent node, like the document object, this property will be equal to null.

For example, the parentNode property on the document.body element will point to the document.documentElement object.

Consider the code below, where we justify this relationship:

document.body.parentNode === document.documentElement; // true

childNodes

The childNodes property of a given element node returns a list of all its child nodes.

More specifically, childNodes returns a NodeList object containing all the children of a given node.

Can you recall which other property/method returns a NodeList object?

Remember that the children can also be text and comment nodes, in addition to element nodes.

Consider the HTML below:

<html>
<head>
    <title>HTML DOM</title>
</head>
<body>
    <p>Experimenting with the DOM.</p>
</body>
</html>

The <html> element here has five child nodes, in the following order:

  1. A text node
  2. The <head> element node
  3. A text node
  4. The <body> element node
  5. A text node

Now you may be thinking where are the three text nodes coming from.

If you notice, there are newlines and indentations after the <html>, </head> and </body> tags. These are text nodes that happen to be the children of the <html> element.

Anyways, inspecting the childNodes property of the documentElement object, we see that it returns exactly the result were expecting:

var children = document.documentElement.childNodes;

console.log(children.length); // 5
console.log();

for (var i = 0, len = children.length; i < len; i++) {
    console.log(children[i].nodeName);
}

The nodeName property of a text node returns the string #text, whereas the one for an element node returns its tagname (uppercased).

5
#text
HEAD
#text
BODY
#text

As expected, we get five children — with three text and two element nodes.

If we remove all these text nodes from the markup, we would end up with only two child nodes of the <html> element, as shown below:

<html><head><title>HTML DOM</title></head><body><p>Experimenting with the DOM.</p></body></html>
var children = document.documentElement.childNodes;

console.log(children.length); // 2
console.log();

for (var i = 0, len = children.length; i < len; i++) {
    console.log(children[i].nodeName);
}
2
HEAD
BODY

Simple as a piece of cake!

previousSibling

As we know from the previous chapter, siblings are nodes with the same parent.

Following from this, the previousSibling property of a given node points to the sibling that comes immediately before it in the HTML markup, or else the value null.

Consider the following code:

<html>
<head><title>HTML DOM</title></head><body>Hello.</body>
</html>

As is obvious, the previous sibling of <head> is a text node, while the previous sibling of <body> is the <head> element.

Let's now see what does the previousSibling property return for each of these elements:

var prevSib = document.head.previousSibling;
console.log(prevSib.nodeName);

prevSib = document.body.previousSibling;
console.log(prevSib.nodeName);
#text
HEAD

As expected, first we get a text node and then the <head> element returned.

nextSibling

Now that you've understood previousSibling, understanding the logic of nextSibling won't be a problem.

For a given node, its nextSibling property points to the sibling that comes immediately after it.

Let's apply this to the same code above:

<html>
<head><title>HTML DOM</title></head><body>Hello.</body>
</html>

The next sibling of <head> is <body>, while the next sibling of <body> is a text node.

As before, let's also check this through code:

var nextSib = document.head.nextSibling;
console.log(nextSib.nodeName);

nextSib = document.body.nextSibling;
console.log(nextSib.nodeName);
BODY
#text

Once again, just what we expected.

Selecting elements only

Often times, while selecting nodes via the traversal properties we saw above, one needs to make sure that the properties return elements only.

People are generally not concerned with other types of nodes. Who would want to process text or comment nodes anyway?

However, as we know, the properties childNodes, previousSibling and nextSibling can all point to non-element nodes — and so to select elements only, we are just left with manual checks.

Fortunately, JavaScript comes with three special properties that operate exactly like childNodes, previousSibling and nextSibling, but that take into account elements only.

They are children, previousElementSibling and nextElementSibling, respectively.

As the names might suggest, these properties are meant to select only element nodes.

Let's see each one...

children

The children property of a given element node returns an HTMLCollection object containing all its children element nodes.

Recall that childNodes returns a NodeList object. This is a clear indicator of the fact that it returns a list with non-element nodes as well.

Consider the code below:

<html>
<head>
    <title>HTML DOM</title>
</head>
<body>
    <p>Experimenting with the DOM.</p>
</body>
</html>

As we have seen above, calling childNodes on documentElement returns a list of five nodes. However, calling children will return only two nodes; both elements:

var childrenElements = document.documentElement.children;

console.log(childrenElements.length); // 2
console.log();

for (var i = 0, len = childrenElements.length; i < len; i++) {
    console.log(childrenElements[i].nodeName);
}
2
HEAD
BODY

previousElementSibling

The previousElementSibling property, of a given element node, returns the sibling element immediately coming before it.

If there isn't any such element, the property returns the value null.

Below shown is an illustration:

<html>
<head>
    <title>HTML DOM</title>
</head>
<body>
    <p>Experimenting with the DOM.</p>
</body>
</html>
var prevElemSib = document.head.previousElementSibling;
console.log(prevElemSib);

prevElemSib = document.body.previousSibling;
console.log(prevElemSib.nodeName);

The previous element sibling of <head> is null, whereas the previous element sibling of <body> is <head>.

null
HEAD

Just remember that previousElementSibling is meant to return element nodes only; whereas previousSibling is meant to return non-element nodes, as well.

nextElementSibling

The nextElementSibling property, of a given element node, returns the sibling element coming immediately after it.

If there isn't any such element, it returns null.

Below shown is an illustration:

<html>
<head>
    <title>HTML DOM</title>
</head>
<body>
    <p>Experimenting with the DOM.</p>
</body>
</html>
var nextElemSib = document.head.nextElementSibling;
console.log(nextElemSib);

nextElemSib = document.body.previousSibling;
console.log(nextElemSib.nodeName);

The next element sibling of <head> is <body>, whereas the next element sibling of <body> is null.

BODY
null

Once again remember that nextElementSibling is meant to return element nodes only; whereas nextSibling is meant to return non-element nodes, as well.

And this is all that we need to perfect in the HTML DOM selection world.

In conclusion

Just like we said before, selecting an element is vital and a must, before being able to play with the potential of the DOM.

Once you've perfected how to select given stuff in an HTML document and then process it one-by-one, in the case of lists, you can consider moving on to explore how to work with HTML DOM elements.

Surely, a fun avenue awaits!