Useful DOM Traversal Methods You May Have Missed
Tags: javascript, html, webdev, beginners
Published: 2020-02-01 02:31:42

**Subscribe to my email list now at http://jauyeung.net/subscribe/**

**Follow me on Twitter at https://twitter.com/AuMayeung**

**Many more articles at https://medium.com/@hohanga**

**Even more articles at http://thewebdev.info/**

The main use of client-side JavaScript is to manipulate web pages dynamically. We can do this with the DOM traversal methods and properties available to DOM Node objects.

Adding or changing child and sibling elements is easy for any given Node since there are properties built into DOM Node objects to perform these actions. The following are methods of a DOM Node object for getting parent, child, and sibling nodes or elements.

appendChild
===========

The `appendChild` methods let us attach a child node to a given HTML element as the last child node of the current node. If the argument referenced an existing node on the DOM tree then the node will be detached from its current position and attached to its new position.

It takes one argument, which is a DOM Node object.

For example, given 2 existing nodes in the following HTML:

```html
<div id='foo'>  
  foo  
</div>  
<div id='bar'>  
  bar  
</div>
```

We can attach the element with ID bar as a child to the element with ID bar as follows:

```javascript
const foo = document.querySelector('#foo');  
const bar = document.querySelector('#bar');foo.appendChild(bar);
```

Once we ran that, we should get the following structure:

```html
<div id="foo">  
  foo  
  <div id="bar">  
    bar  
  </div>  
</div>
```

We can also use it to create an element that’s created on the fly. For example, if we have the following HTML:

```html
<div id='foo'>  
  foo  
</div>
```

Then we can write the following code to attach a new `p` element to the div with ID foo:

```javascript
const foo = document.querySelector('#foo');  
const bar = document.createElement('p');  
bar.textContent = 'bar';
foo.appendChild(bar);
```

In the code above, we used `createElement` to create a new `p` element. Then we set the `textContent` property to add text inside the `p` element. At the end, we can `appendChild` on `foo` with `bar` as the argument to attach `bar` as the child of `foo` .

cloneNode
=========

The `cloneNode` method clones a Node object and optionally, all of its content. It doesn’t clone all the content of the Node by default.

It takes one argument, which is an optional argument indicate if it’s a deep clone, which means everything will be cloned. `true` means do a deep clone and `false` otherwise.

For example, given the following HTML:

```html
<div>  
  foo  
</div>
```

We can write the following JavaScript code to clone the div and then attach it to the `body` element as the last child:

```javascript
const fooDiv = document.querySelector('div');  
const fooClone = fooDiv.cloneNode(true);  
document.body.appendChild(fooClone);
```

We pass in `true` to the `cloneNode` method to clone everything. Then we call `appendChild` on `document.body` with the cloned object passed in as the argument to add it as the child of `body`.

compareDocumentPosition
=======================

The `compareDocumentPosition` method compares the position of the given node against another node in any document. It takes a DOM Node object as its argument.

It returns a bitmask with the following possible values

*   `DOCUMENT_POSITION_DISCONNECTED` — 1
*   `DOCUMENT_POSITION_PRECEDING` — 2
*   `DOCUMENT_POSITION_FOLLOWING` — 4
*   `DOCUMENT_POSITION_CONTAINS` — 8
*   `DOCUMENT_POSITION_CONTAINED_BY` — 16
*   `DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC` — 32

For example, given the following HTML:

```html
<div id='foo'>  
  foo  
</div>  
<div id='bar'>  
  bar  
</div>
```

We can write the following JavaScript to compare the position of the div with ID foo and the one with ID bar:

```
const foo = document.querySelector('#foo');  
const bar = document.querySelector('#bar');const relativePos = foo.compareDocumentPosition(bar);  
console.log(relativePos);
```

The code above should get us 4 for `relativePos`, which means the element with ID bar follows the element with ID foo.

contains
========

The `contains` method checks if a DOM node is inside the given node. It takes one argument, which is a Node object that we want to check if it’s inside the one that this method is called on.

It returns `true` if the node in the argument is inside the one that’s called and `false` otherwise.

For example, given the following HTML:

```html
<div id='foo'>  
  foo  
</div>  
<div id='bar'>  
  bar  
</div>
```

Then we can write the following JavaScript to check if the div with ID bar is inside the div with ID foo:

```javascript
const foo = document.querySelector('#foo');  
const bar = document.querySelector('#bar');const fooContainsBar = foo.contains(bar);  
console.log(fooContainsBar);
```

Of course, `fooContainsBar` should be `false` since the div with ID foo isn’t inside the div with ID bar.

On the other hand, if we have the following HTML instead:

```html
<div id='foo'>  
  foo  
  <div id='bar'>  
    bar  
  </div>
</div>
```

Then with the same JavaScript code as the first example, `fooContainsBar` should `true` since div with ID foo is inside the div with ID bar.

getRootNode
===========

The `getRootNode` method returns the Node object’s root, which optionally includes the shadow root if it’s available.

It takes an optional argument with an object with the following properties:

*   `composed` — a boolean that indicates rather the shadow root should be included. It defaults to `false`

It returns the Node that either returns an element that’s the root of the given Node or the shadow root will be returned for elements inside the shadow DOM.

For example, if we have the following HTML:

```html
<div id='foo'>  
  foo  
</div>
```

Then we can call the `getRootNode` method as follows:

```javascript
const foo = document.querySelector('#foo');
const root = foo.getRootNode();  
console.log(root);
```

We should get the HTML document as the root node since it’s not inside a shadow DOM.

The root will be the shadow root for Web Components. For example, if we have the following web component:

```javascript
customElements.define('custom-p',  
  class extends HTMLElement {  
    constructor() {  
      super(); const pElem = document.createElement('p');  
      pElem.id = 'p-element';  
      pElem.textContent = 'shadow p' 
      const shadowRoot = this.attachShadow({  
        mode: 'open'  
      });  
      shadowRoot.appendChild(pElem);  
    }  
  }  
);
```

And we have the Web Component added in the HTML code:

```javascript
<custom-p></custom-p>
```

Then we can get the root node of the element with the ID `p-element` by writing:

```javascript
const pElement = document.querySelector('custom-p').shadowRoot.querySelector('#p-element');  
const rootNode = pElement.getRootNode();  
console.log(rootNode);
```

First, we get the custom element, then we get the `shadowRoot` property which lets us access the shadow DOM of our `custom-p` web component. Then we can get the `p` element with the ID `p-element` with the shadow root.

After that, we get the root node of it by calling`getRootNode` on `pElement` which represents `p` element with the ID `p-element` .

The `console.log` should get us the shadow root of the Web Component.

Conclusion
==========

With these DOM traversal methods, we can set the nodes however we like for simple situations. Also, there’re methods to check whether an element is the child of another one, and also to get the root node of the given element.