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
Internet explorer lower than 9 also lists comment nodes in children.
In the example document:
- Write the code to access the
ULusingchildren. - Write the code to access the second
LIusingchildren.
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.
Children links
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
parentNodeproperty references the parent node. It equalsnullfordocument.documentElement. - The
previousSiblingandnextSiblingallow 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... */)
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 ?
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.