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.

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 a DOM object 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.

And once we've got access, we can literally do anything with the DOM element.

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, later in the next chapter.

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 commonly used to aid in selecting elements in CSS, is the class attribute. Well, it's also useful in selecting elements in JavaScript!

To fetch a bunch of elements with a given class value, 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 with that class name.

To be precise, it returns an HTMLCollection list that carries all the given DOM elements within it.

The HTMLCollection list is referred to as array-like, since it resembles arrays in JavaScript. That is, it also has indexes like 0, 1, 2... as well as a length property.

However, mind you that it isn't an actual Array instance - it doesn't has any of the methods available to arrays, and is therefore only like an array!

Since getElementsByClassName() returns a list of selected elements, 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 indexes - just like how indexes operate in arrays.

For details on how to work with indexes in arrays, consider reading JavaScript Arrays Basics Concepts.
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 HTMLCollection in a for loop is extremely easy - it also has length property, akin to arrays, which is used to keep track of a counter variable.

Below shown is the rewritten version of the 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

As you can justify, both these versions do exactly the same thing - log the content of each p element.

The former is much useful when you have only one (or sometimes even two) element to deal with. The latter is much more useful when you have to play with 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 does the search for elements with given tag names rather than elements with 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 will fetch all the <p> elements shown above and log 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.

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"),
     eleList = main.getElementsByClassName("small");

console.log(eleList.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 a 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; saved inside eleList.

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

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

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

And, it has been confirmed!

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() method 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.

In behaviour, it's essentially the same as HTMLCollection, so you won't ever notice the difference directly.

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. Likewise we'll use the querySelectorAll() method with the desired CSS selector:

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(sel) is same as calling querySelectorAll(sel)[0].

Pre-defined DOM collections

Apart from the methods we saw above to select given elements, HTML DOM comes equipped with some predefined properties on the document object that have some common HTML elements pre-selected.

Below shown is the list:

  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, if we want 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.

In the coming chapters we'll be, at least, using the first three properties pretty frequently - 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.

first are using the childNodes and parentNode properties, however it is not so common to do so since the DOM tends to create many empty text nodes, at indentations and line-breaks, that can disrupt in the behaviour of some properties and methods as we traverse down the children. In such cases we have properties like children.

Fetching elements this way is usually done when we want to add or remove elements from a document. We will discuss on this later in a coming chapter. Let's just show you how the properties parentNode and childNodes work: We are using the same HTML code as in the selector section above and even some of the properties discussed above.

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 yoy 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 it 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 in each of these cases

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 <body> 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.

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

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

Once again, simple as a cake!

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 would just be left with manual checks.

They are children, previousElementSibling and nextElementSibling.

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 childrenEle = document.documentElement.children;

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

for (var i = 0, len = childrenEle.length; i < len; i++) {
    console.log(childrenEle[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 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!