Traversing the DOM

  1. The root: documentElement and body
  2. Child elements
    1. childNodes
    2. children
  3. Children links
    1. The firstChild and the lastChild
    2. parentNode, previousSibling and nextSibling
  4. Summary

An access always starts from the document.
This object provides a variety of methods to search and modify elements.

The root: documentElement and body

The root is the DOM always document.documentElement. This special property will give access to the topmost HTML tag.

Another starting point can be the document.body, which represents the BODY tag.

Both entry points are valid. But document.body can be null.

For example, you access document.body from an inline script in the HEAD, prepare to see null instead. That’s natural, because there is no BODY yet.

In the example below, first alert outputs null:

<!DOCTYPE HTML>
<html>
    <head>
        <script>
            alert("Body from HEAD: "+document.body) // null
        </script>
    </head>
    <body>
        <div>The document</div>

        <script>
            // different browsers output different text here, 
            // because of different implementations of toString 

            alert("Body from inside body: " + document.body) 
        </script>
    </body>
</html>
Open the code in new window

Contrary to this, document.documentElement is available always.

Also note that document.body can’t be undefined. In the world of DOM, an “element not found” or “no such element” is always null.

As a more general rule than described above, it is impossible to reference elements that are not yet rendered at the time of script execution.

Child elements

There are several ways to obtain element children.

childNodes

An element keeps references to children in childNodes array-like property.

All nodes are referenced, including whitespace ones (excepts IE<9).

<!DOCTYPE HTML>
<html>
  <body>
    <div>Allowed readers:</div>
    <ul>
      <li>Bob</li>
      <li>Alice</li>
    </ul>

    <!-- a comment node -->

    <script>   
      function go() {
        var childNodes = document.body.childNodes

        for(var i=0; i<childNodes.length; i++) {
            alert(childNodes[i])
        }
      }
    </script>

    <button onclick="go()" style="width:100px">Go!</button>

  </body>
</html>
Open the code in new window

Note that SCRIPT node is listed too.

In the example document above, document.body.childNodes[1] is DIV in all browsers except IE<9. In older IEs, there are no whitespaces, so document.body.childNodes[1] is UL.

children

Sometimes we need to browse only element nodes, skipping text nodes. That’s what the children property is for.

It contains all element nodes. Check out the same example as above, but with children instead of childNodes.

It will output only element nodes as it should.

<!DOCTYPE HTML>
<html>
  <body>
    <div>Allowed readers:</div>
    <ul>
      <li>Bob</li>
      <li>Alice</li>
    </ul>

    <!-- a comment node -->

    <script>   
      function go() {
        var children = document.body.children

        for(var i=0; i<children.length; i++) {
            alert(children[i])
        }
      }
    </script>

    <button onclick="go()" style="width:100px">Go!</button>

  </body>
</html>
Open the code in new window

Comment nodes in `children` if IE<9

Internet explorer lower than 9 also lists comment nodes in children.

In the example document:

  • Write the code to access the UL using children.
  • Write the code to access the second LI using children.
Open solution
Solution

The code is cross-browser:

document.body.children[1]
document.body.children[1].children[1]

It works fine, because there are no comment nodes before UL, so children indexes are same for IE<9 and other browsers.

Getting a list of children is not enough for convenient walking around elements.
So, there are additional properties for siblings, parent, etc.

The firstChild and the lastChild

The firstChild and lastChild properties allow to quickly access first or last child.

They are basically same as corresponding childNodes indexes:

var body = document.body

alert(body.firstChild === body.childNodes[0])
alert(body.lastChild === body.childNodes[body.childNodes.length-1])

parentNode, previousSibling and nextSibling

  • The parentNode property references the parent node. It equals null for document.documentElement.
  • The previousSibling and nextSibling allow to access the left or the right neightbour.

For example:

<!DOCTYPE HTML>
<html>
<head>
   <title>My page</title>
</head>
<body>
    <div>The header</div>

    <ul><li>A list</li></ul>

    <div>The footer</div>
</body>

</body>
</html>
Open the code in new window

Picture for the document above (without whitespace nodes):

The browser always maintains correct helper links. It is possible to modify the DOM, add/remove elements, but no need to reassign the links manually, browser does that.

Write the code to check if the DOM Node elem is totally empty. That is, there are no children or text in it.

if (/*... put here your code to check if the elem is empty... */)

Open solution
Solution

There are many ways:

if (elem.childNodes.length) { ... }

if (elem.firstChild) { ... }

if (elem.lastChild) { ... }

The last one appears to be the shortest.


Is it right that document.body.lastChild.nextSibling is always null?

.. Same question about document.body.children[0].previousSibling ?

Open solution
Solution

The answers are ‘Yes’ and then ‘No’.

The first expression is always null, that’s right. The document.body.lastChild is last and has no siblings.

The second expression maybe either null or a text node. That’s because document.body.children[0] is a first element child, it may have a text node as the previousSibling.

Summary

The DOM tree is tightly interlinked:

up
parentNode
down
children/childNodes, firstChild, lastChild
left/right
previousSibling/nextSibling

Browser guarantees that the links are always correct. All of them are read-only.

If there is no such element (child, parent, neighbour etc), the value is null.

Tutorial

Donate

Donate to this project