Edit Page

The Document Object Model (DOM)

Introduction

JavaScript allows us to create dynamic interactive web applications. This is due to the Document Object Model (DOM) interface that represents the HTML document as a tree of nodes.

The HTML DOM Tree of Objects

An object in the DOM is called a node. The DOM has some built-in nodes such as document and document.body and HTML element nodes such as <div> or <p>. A node can also be a textNode, which refers to a text contained in an element such as <p>some text</p> or a comment node for comments such as <!-- comment -->. Below is a summary of the most commonly used node types in the DOM.

Node TypeExample
ELEMENT_NODEAny HTML element such as <p>, <ul>, <div>, etc.
ATTRIBUTE_NODEAny attribute of an Element such as href in <a> or src in img
TEXT_NODEThe actual text inside an Element or Attribute such as <p>text</p> or <img src="./some-image.png">
COMMENT_NODEA Comment node as in <!-- this is a comment -->
DOCUMENT_NODEA Document node that represents any web page loaded in the browser

Most web browsers use tabs and each tab is represented by its own Window object. Each window object has a document property that refers to the DOM, which represents the content of the window. The DOM enables creating interactive web pages, where we can add, change, or delete any HTML elements and attributes, CSS styles, or events dynamically. We will explore the main parts of the DOM API that enable these capabilities.

Below is an example of how an HTML document is represnted in the DOM tree:

<!DOCTYPE html>
<html>
<head>
    <title>My Title</title>
</head>
<body>
    <div class="content">
        <ul id="menu">
            <li>Home</li>
            <li>About</li>
        </ul>
    </div>
</body>
</html>
Example of DOM hierarchy in an HTML document
Example of DOM hierarchy in an HTML document

How to query or select individual elements from a document?

We can query for elements using:

  1. Element Id values document.getElementById(id)
  2. Element tag names document.getElementsByTagName(name)
  3. Element names document.getElementsByName(name)
  4. CSS selectors document.querySelector(selectors) and document.querySelectorAll(selectors)

1. Using document.getElementById

The Document method document.getElementById(id) returns an Element that matches the given id value.

1
2
3
4
5
6
7
8
<h1 id="title">Title 1</h1>
<h1>Title 2</h1>
<p id="article">content</p>

<script>
  let elem = document.getElementById("title");
  console.log(elem.innerText);
</script>

Console Output:

Title 1

2. Using document.getElementsByTagName

The Document method document.getElementsByTagName(name) returns a NodeList of Elements that match the given Element tag name (e.g., p, h1, table, etc.).

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
    <h1 id="title">Title 1</h1>
    <h1>Title 2</h1>
    <p id="article">content</p>

    <script>
        let elems = document.getElementsByTagName("h1");
        for (let i = 0; i < elems.length; i++) {
            console.log(elems[i].innerText);
        }
    </script>

Console Output:

Title 1
Title 2

3. Using document.getElementsByName

The Document method document.getElementsByName(name) returns a NodeList of Elements that match the given name attribute (e.g., name="hobby").

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
    <h3>Outdoor Hobbies:</h3>
    <input name="hobby" type="checkbox" id="volleyball" value="Volleyball">
    <label for="volleyball">Volleyball</label>
    <input name="hobby" type="checkbox" id="football" value="Football">
    <label for="football">Football</label>
    <input name="hobby" type="checkbox" id="basketball" value="Basketball">
    <label for="basketball">Basketball</label>
    <input name="hobby" type="checkbox" id="tennis" value="Tennis">
    <label for="tennis">Tennis</label>

    <script>
        let elems = document.getElementsByName("hobby");
        for (e of elems) {
            console.log(e.value);
        }
    </script>

Console Output:

Volleyball
Football
Basketball
Tennis

4. Using document.querySelector() or document.querySelectorAll()

We can also use CSS selectors for describing elements or sets of elements within a document. The Document methods document.querySelector() and document.querySelectorAll() allow us to find elements if they match the given CSS selector.

  • document.querySelector() returns the first Element that matches the specified CSS selector.
  • document.querySelectorAll() returns a NodeList of all Elements that match the specified CSS selector.

Please refer to the previous lecture notes on CSS selectors for usage and syntax.

Note: Many browsers won’t match for psudeo-selectors (e.g., :visited) and psudeo-elements (e.g.,::first-line) when used with document.querySelector() or document.querySelectorAll() for the privacy of users as this may expose their browsing history.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
  <div class="box">
      <a href="#">Link #1, in the div.</a>
      <a href="#">Link #2, in the div.</a>
      <p>p in the div.
          <a href="#">Link #3, in the p that's in the div.</a>
      </p>
  </div>
  <script>
      console.log("Using document.querySelector()");
      let oneElem = document.querySelector(".box > a:first-child");
      console.log(oneElem.innerText);
      let AllElems = document.querySelectorAll(".box > a");
      console.log("Using document.querySelectorAll()");
      for (e of AllElems) {
          console.log(e.innerText);
      }
  </script>

Console Output:

Using document.querySelector()
Link #1, in the div.
Using document.querySelectorAll()
Link #1, in the div.
Link #2, in the div.

How to modify the style of any document element?

We can use the document methods above to get elements and change their style in the form of element.style.<cssProperty>, where the CSS property’s name is specified in a camelCase form

As a general rule of thumb, in order to get the style property name in JavaScript, you should change any hyphenated CSS property’s name to camelCase.

css propertyJavaScript property
background-colorbackgroundColor
margin-topmarginTop
text-decorationtextDecoration
colorcolor

Below is an example on how to change the background of a <div> element in JavaScript:

document.getElementsByTagName("div")[0].style.backgroundColor = "red";

How to add or change attributes of any document element?

We can use the document methods above to query or get elements and change their attributes in the form of element.<attribute_name> as shown below:

<a id="myLink" href="#">CPIT-405</a>
<script>
  document.getElementById("myLink").href= "https://cpit405.gitlab.io/";
</script>

How to query, set, and modify the content of a document?

We can use the document methods above to query or get elements and change their content using element.innerText, to get or set the rendered text of an element node and its descendants or element.innerHTML, which is used to get or set the HTML markup contained within the element.

<a id="myLink" href="https://cpit405.gitlab.io/"></a>
<div id="codeBlock"></div>
<script>
  document.getElementById("myLink").innerText = "CPIT-405";
  document.getElementById("codeBlock").innerHTML = 
  `<ul id="list">
      <li><a href="#">Item 1</a></li>
      <li><a href="#">Item 2</a></li>
      <li><a href="#">Item 3</a></li>
   </ul>`;
</script>
60%

How to traverse a document? How to find the ancestors, siblings, and descendants of an element?

Once an element is selected (e.g., using document.getElementById()), we can traverse the element and its children using .children, .firstElementChild, .nextElementSibling, lastChild, etc. Below is an example that shows how to traverese the DOM to apply a 20% discount to the prices of a list of items.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
    <input type="button" value="Apply 20% Discount" onclick="handleClick()">
    <h2>External Storage</h2>
    <ul id="products">
        <li>
            <span>External HDD 1TB: $</span>
            <span>49.99</span>
            <span></span>
        </li>
        <li>
            <span>External HDD 2TB: $</span>
            <span>89.99</span>
            <span></span>
        </li>
        <li>
            <span>External SSD GB512: $</span>
            <span>59.99</span>
            <span></span>
        </li>
    </ul>
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
function handleClick() {
    document.getElementsByTagName("input")[0].disabled = true;
    // get the <ul> elements
    let ulElem = document.getElementById("products");
    if (ulElem.hasChildNodes()) {
        // get all <li> elements
        let liChildren = ulElem.children;
        // for each <li> element, get the second span and last span
        for (let i = 0; i < liChildren.length; i++) {
            // get the second span that contains the current price
            let priceSpan = liChildren[i].firstElementChild.nextElementSibling;
            priceSpan.style.textDecoration = "line-through";
            let currentPrice = parseFloat(priceSpan.innerText);
            // get the last span that will contain the discounted price
            let newPriceSpan = liChildren[i].lastElementChild;
            newPriceSpan.innerText = "$" + (currentPrice - (currentPrice * .20)).toFixed(2);
        }
    }
}
60%

How to find the closest element to an element?

We can use the element’s .closest() method to traverse the Element and its parents (moving up the DOM tree toward the document root) until it finds a node that matches the given selector string.

Suppose we want to style the closest ul element to a list of items on a page that has multiple nested ul elements:

20
21
22
23
24
25
26
27
28
29
30
31
32
<div>
  <div>
    <ul>
      <li>Breakfast
        <ul>
          <li>omelette<span>$5.00</span></li>
          <li>Waffle<span>$6.00</span></li>
          <li>Pancake<span>$6.00</span></li>
          <li>Shakshouka<span>$9.00</span></li>
        </ul>
      </li>
    </ul>
  </div>
20
21
var el = document.getElementsByTagName('span')[0];
el.closest("ul").style.border = "1px solid black"
60%

How to modify the structure of a document by creating, inserting, and deleting nodes?

Creating and inserting new elements

We can use document.createElement to create an HTML element and document.createTextNode to create a text node for the text value inside of an element. We can also use <Element>.appendChild to add a node to the end of the list of children of a parent node.

60%

How to insert text before or after an element or an element’s text using insertAdjacentText?

We can use insertAdjacentText(where, text) to insert text before an element, at the beginning of the element’s text, at the end of the element’s text, or after the element itself. The insertAdjacentText method takes a position relative to the element and a text value. The following are the possible positions:

positionDescription
beforebeginBefore the element itself.
afterbeginInside the element but before its first child.
beforeendInside the element but ater its last child.
afterendAfter the element itself.
<!-- beforebegin -->
<p>
  <!-- afterbegin -->
  text value
  <!-- beforeend -->
</p>
<!-- afterend -->

Example:

60%

How to insert HTML before or after an element or an element’s child nodes using insertAdjacentHTML?

The insertAdjacentHTML(where, text) is like the insertAdjacentText but with inserting HTML as a string instead of text.

60%

How to delete a document element from the DOM tree?

We can use the elemen’ts .remove() method to remove elements from the DOM tree.

60%