HTMLCollection vs NodeList

Hi, in this post we are going to learn the difference between HTMLCollection and NodeList.

HTMLCollection and NodeList: there are similar structures, they are groups of thing in our web page and depending which method we are using when we play with the DOM then we get a NodeList or HTMLCollection.

For example: In the post DOM querySelector and querySelectorAll we learned that when we use the querySelectorAll this going to return us the list of the nodes in a NodeList format and if we use .getElementsByTagName() this method will return us a HTMLCollection with the elements.

What is HTMLCollection?

  • HTMLCollection is elements only, so only element nodes.
  • HTMLCollection is consider LIVE that means if we are updating our web application and we have a variable that holding the HTMLCollection; for example if we add another element to that collection then the variable also will change or will be update with counting the new element that was added.

What is NodeList?

  • NodeList is any type of nodes, it could include text nodes, element nodes, document nodes, document fragment nodes, etc.
  • NodeList is NOT LIVE because if you update your web application the variable that holds this NodeList does NOT will be updated. Also called static list.

Ok, now there is a property called .childNodes and property called .children

The .children property return a HTMLCollection so is LIVE and are elements only, and the .childNodes property return nodes and NOT LIVE.

Let’s see our Layout & code:

View of the layout (Browser view)

HTML

<!DOCTYPE html>

<!-- this comment is a child of the document -->

<html lang="en">

    <head>
        <meta charset="UTF-8">
        <title>Nodelist Vs HTMLCollections</title>
        <meta name="viewport" content="width=device-width">
        <link rel="stylesheet" href="styles.css">
        <!-- This comment is a child element of the head element -->
    </head>

    <!-- I'm a comment that is a child of the html element -->

    <body>
        <h1>Heading</h1>

        <main id="main">

            <section id="a">
                <p>Section A has five paragraphs. Each paragraph is a Child Element Node of the section Element Node. The text inside each paragraph tag is a Text Node.</p>
                <p>Eligendi porro fuga velit libero suscipit temporibus repellendus facilis molestias, eaque modi reiciendis aut incidunt voluptas.</p>
                <p>Saepe autem voluptates, quibusdam, quis provident hic, ab tenetur placeat numquam maxime, amet sunt rerum. Nemo distinctio alias</p>
                <p>Excepturi, iure, unde. Eos fugiat quos aperiam fuga minima esse quisquam corrupti dolore tempora ad ex nulla, explicabo, fugi</p>
                <p>Necessitatibus officiis, dolosumenda repellat voluptatem aut et! Placeat perferendis reprehenderit, cumque iste tempore aut.</p>
            </section>

            <section id="b">
                <p>Section B has four paragraphs. Lorem ipsum dolor sit amet, us beatae vel illum mollitia fugiat modi aperiam excepturi natus quisquam ab molestias, expsoluta.</p>
                <p>Eligendi porro fuga velit libero suscipit temporibus repellendus facilis molestias, eaque modi reiciendis aut incidunt voluptas saepe assumenda omnis aperixplicabo.</p>
                <p>Saepe autem voluptates, quibusdam, quis pro. Nemo distinctio alias inventore rem doloribus, nostrum magni natus illo reprehenderit provident pariatur explicabo officia.</p>
                <p>Excepturi, iure, unde. Eos fugiat quos aperiam fuga minima esse quisquam corrupti dolore tempora ad ex nulla, explicabo, fugit reicitur quo totam laborum!</p>
            </section>

            <!-- I'm a comment node after the two sections -->
        </main>

        <script src="script.js"></script>

    </body>
</html>

JSHTMLCollection

// Getting the main element
let main = document.getElementById('main');

// Object with different type of nodes
let nodeTypes = {
    1: 'Element',
    3: 'Text',
    8: 'Comment',
    9: 'Document',
    10: 'DocType',
    11: 'Document Fragment'
};

// Getting the elements of main element
// Elements only, HTMLCollection
let mainChildren = main.children;   // HTMLCollection(2) [section#a, section#b, a: section#a, b: section#b]

// Going through every element in the mainChildren
for (let i = 0; i < mainChildren.length; i++) {

    let nt = mainChildren[i].nodeType; // .nodeType property is an integer that identifies what the node is, for example will return type 1
    
    // Comparing the tn number where the nodeTypes object and see wich value is
    console.log('main.children ===>', i, nodeTypes[nt]); // 1 is element, 3 is text, 8 comment see Oficial documentation
}

Result:

The variable mainChildren hold this HTMLCollection with 2 elements

And those elements are type:

IMPORTANT NOTE: If we want to use a forEach or a .map() methods instead a “for loop” in a HTMLCollection this will NOT BE possible, in that case to use a forEach you will need to convert that HTMLCollection to an Array. Example:

Array.from(mainChildren).forEach((element) => console.log(element));

JSNodeList

// Getting the main element
let main = document.getElementById('main');

// Object with different type of nodes
let nodeTypes = {
    1: 'Element',
    3: 'Text',
    8: 'Comment',
    9: 'Document',
    10: 'DocType',
    11: 'Document Fragment'
};

// Getting the nodes of main element
let mainChildNodes = main.childNodes;  // Nodes, NodeList 
console.log('mainChildNodes --->', mainChildNodes);

// Going through every node in the mainChildren
for (let n = 0; n < mainChildNodes.length; n++) {

    let nt = mainChildNodes[n].nodeType;  // .nodeType property is an integer that identifies what the node is, , for example will return type 1 or type 3

    // Comparing the tn number where the nodeTypes object and see wich value is
    console.log('main.childNodes', n, nodeTypes[nt]); // 1 is element, 3 is text, 8 comment see Oficial documentation
}

Result:

The variable mainChildNodes hold this NodeList with 7 nodes

And those nodes are type:

NOTE: NodeList come with forEach() method, keys, values, entries. But if you want to use .map() method in a NodeList you need to convert the NodeList to an array.

Array.from(mainChildNodes).map((element) => console.log(element));

Nice, if finally we want to know the nodes of the document it self we need to use document.childNodes:

// Getting the main element
let main = document.getElementById('main');

// Object with different type of nodes
let nodeTypes = {
    1: 'Element',
    3: 'Text',
    8: 'Comment',
    9: 'Document',
    10: 'DocType',
    11: 'Document Fragment'
};

// Getting all the child nodes that the actual document have
let doc = document.childNodes;

// Going through every node in the document
for (let c = 0; c < doc.length; c++) {

    let nt = doc[c].nodeType; // .nodeType property is an integer that identifies what the node is, , for example will return type 1 or type 3
    
    // Comparing the tn number where the nodeTypes object and see wich value is
    console.log('document.childNodes', c, nodeTypes[nt], doc[c].nodeName);
}

Result:

By Cristina Rojas.