Jump to main content
Menu

Walking the DOM and Modifying Nodes

Walking the DOM

  • In addition to selector methods, it is also possible to move around within the DOM tree in a more methodical fashion, accessing parent nodes, child nodes, siblings, etc.
  • Often you would use a selector method to pinpoint an element, or create a node list of elements to loop through, and then "walk" from there to a parent element node, a child node, a sibling node, etc.
  • All of these properties and methods are part of the DOM, which means that they will work in XML documents too.

Methods and Properties for Walking the DOM

  • childNodes[] - Stored as a dynamic node list and indexed by number; allows access to the children nodes one level down in the document tree. To access children even further down (grandchildren, great-grandchildren) requires further document path information. Has a length property reflecting the number of child nodes.
  • closest("CSS selector") - This method accepts a CSS selector as a string and finds the closest ancestor element node that matches the CSS. Returns null if no match is found.
  • firstChild - The first child node of the currently accessed element node. This could be a text node or comment node.
  • firstElementChild - The first child element node of the currently accessed element node. Ignores text nodes and comment nodes.
  • lastChild - The last child node of the currently accessed element node. This could be a text node or comment node.
  • lastElementChild - The last child element node of the currently accessed element node. Ignores text nodes and comment nodes.
  • nextSibling - The next node at the same level of the document tree; they have the same parent node. This could be a text node or comment node.
  • nextElementSibling - The next element node at the same level of the document tree. Ignores text nodes and comment nodes.
  • previousSibling - The previous node at the same level of the document tree; they have the same parent node. This could be a text node or comment node.
  • previousElementSibling - The previous element node at the same level of the document tree. Ignores text nodes and comment nodes.
  • parentNode - The parent node of the currently accessed element. Each node can have only one parent node (which is guaranteed to be an element node).

Walking the DOM Example

See the Pen Walking the DOM by Jason Withrow (@jwithrow) on CodePen.

Inspecting a Node

In some cases (such as when moving up and down the DOM tree / hierarchy), it is beneficial to know what node you are currently accessing or some details about that node. These properties provide that information.

Property / Method Description Node
hasAttribute("attributename") This method is passed a single parameter, which is a string containing the attribute name.

Returns true if that attribute has been defined; false if it is not defined.

Element
hasAttributes() Returns true if the selected node has at least one attribute defined; false if there are no attributes defined. Element
hasChildNodes() Returns true if the selected node has child nodes; false if there are no child nodes. Element
nodeName Returns the name of the node.
  • If it is a text node then the value returned will be #text.
  • Comment nodes return #comment.
  • The document node (<html></html>) returns #document.
  • Otherwise it will return the name of the element or attribute; these are strings in all-uppercase.
Any
nodeType Returns a number to represent node type:
  • 1 for element node
  • 2 for attribute node
  • 3 for text node
  • 4 for CDATA sections
  • 8 for comments
  • 9 for the document node (<html></html>)
Any
tagName Returns the name of the tag.

Not as versatile as nodeName, because it only works for element nodes.

Element

Getting and Setting Element Node Properties / Attribute Nodes

Dot Notation

  • Dot notation (e.g., elementNodeReference.property) is a well-established and reliable method of reading and setting properties.
  • Implementation considerations:
    • When referencing the href property of an anchor (<a></a>) using dot notation the absolute URL is always returned. This is a good thing; it is consistent cross-browser.
    • Some properties need to be written in camelCase (such as tabIndex, colSpan, and rowSpan) to work across all browsers. The capitalization of these in your HTML code makes no difference.
  • There are some limitations of dot notation:
    • Reserved words cannot be used in the dot notation, so class becomes className.
    • Every dot requires an object lookup, but these are short chains so the performance hit is negligible.

Square Braces Notation

  • Also called subscript notation; this is an alternative to dot notation.
  • What is expressed in dot notation as theLink.title = 'Example' is expressed as theLink['title'] = 'Example'
  • The primary advantage of this approach is that it represents the property / method as a string, which enables reserved words to be used and allows you to assemble the property name on-the-fly (in contrast, dot notation values are literals and cannot be assembled using + and variables).
  • I typically use this notation only when I need its string concatenation flexibility and dynamic nature.

getAttribute() and setAttribute()

  • The dot notation and square braces notation are both parts of JavaScript Core, which means that the syntax is part of the JavaScript language.
  • In contrast, getAttribute() and setAttribute() are DOM methods that can be called for element nodes.
  • getAttribute() retrieves the value of the indicated attribute, which is passed as a string inside the parentheses.
    const idVal = elementRef.getAttribute("id");
    
  • setAttribute() is passed two strings, the first of which is the attribute and the second is the new value.
    elementRef.setAttribute("id","topnav");
    
  • These two DOM methods have the advantage of working with XML documents as well as HTML documents.
  • HTML5 introduced custom data- attributes, which is any attribute starting with data-. These are very useful and getAttribute() and setAttribute() are ideal for working with them.

    Attributes can have as many hyphen-separated words as desired (e.g., data-current-state="inactive" in the HTML). To get and set this custom attribute via JavaScript:

    const elState = elementRef.getAttribute("data-current-state");
    elementRef.setAttribute("data-current-state","active");
    

The classList API

  • Working with the class attribute in HTML is a common occurrence.
  • Classes are unique in allowing multiple space-separated values to be provided (the vast majority of HTML attributes only support a single value, or a single "token" in the language of the specifications).
  • Historically, this multi-value setup has meant that JavaScript approaches have needed to carefully manipulate the string of space-separated values, to avoid damaging or accidentally removing something within that string.
  • The .className property treats the entire class attribute value as one readable / writable string. For some purposes, this is fine. For more complicated situations, something more is needed.
  • The classList API was created for these more complicated scenarios, as it treats all the individual classes assigned to an element as a live collection of tokens that can be modified.

classList Methods

  • add() - Accepts one or more quoted classes, to add to what is already there.
    elementRef.classList.add("someclass");
    
  • remove() - Removes one or more quoted classes, if they exist.
    elementRef.classList.remove("someclass");
    
  • replace() - Accepts two quoted class names. The first is the one to find; the second is the class to replace it with.
    elementRef.classList.replace("classToSwapOut", "replacementClass");
    
  • toggle() - Accepts a single quoted class name as the first parameter and an optional second parameter, if there is conditional logic that needs to be true for the toggle to happen.

    If the toggle goes forward and the class is already there, it is removed. If it is not there yet, it is added.

    // single parameter
    elementRef.classList.toggle("someclass");
    
    // 2 parameters
    elementRef.classList.toggle("someclass", x > 5);
    
  • contains() - Accepts a single quoted class name. If the class is already present, it returns true, otherwise it returns false.
    elementRef.classList.contains("someclass");