Node Properties: Type, Tag and Contents
Mastering the Document Object Model (DOM) is essential for any web developer looking to manipulate web pages dynamically. This article delves deep into the core
Every node in the DOM tree is a JavaScript object, and that object exposes properties that tell you what kind of node it is, what tag it represents, and what content it holds. Once you can read these properties confidently, navigating and editing a page becomes far less error-prone. This chapter covers the node class hierarchy, the type and name properties (nodeType, nodeName, tagName), and the four content properties you will reach for daily (textContent, innerHTML, outerHTML, and nodeValue/data) — including when each is safe to use.
If you have not yet seen how the DOM is structured as a tree, read Understanding the DOM Nodes first.
The node class hierarchy
DOM objects do not all share the same set of properties. They are arranged in a class hierarchy, where each class adds capabilities to the one above it:
Node— the base class. Every node (element, text, comment, document) inherits from it. It provides generic properties such asnodeType,nodeName,nodeValue,parentNode, andchildNodes.Element— a node that is a tag. AddstagName,innerHTML, attributes,children, and query methods.HTMLElement— the base for every concrete HTML element. Subclasses likeHTMLInputElement,HTMLAnchorElement, andHTMLTableElementadd tag-specific properties (e.g.input.value,a.href).TextandComment— leaf nodes that hold text. They inherit fromCharacterData, which adds thedataproperty.
Knowing this hierarchy explains why a <div> has innerHTML but a text node does not: innerHTML lives on Element, and a text node is not an element. You can confirm an object's class with Object.prototype.toString or the constructor name:
const div = document.createElement('div');
console.log(div.constructor.name); // "HTMLDivElement"
console.log(div instanceof HTMLElement); // true
console.log(div instanceof Element); // true
console.log(div instanceof Node); // trueNode types and names
Node types (nodeType)
The nodeType property is an integer that identifies the category of a node. It is read-only and is the most reliable way to branch your logic while traversing the DOM, because text and comment nodes are easy to confuse with elements. The most common values are:
1— Element node (Node.ELEMENT_NODE): an HTML or XML tag such as<div>or<p>.2— Attribute node (Node.ATTRIBUTE_NODE): legacy; modern code reads attributes withgetAttribute()/setAttribute()instead of walking attribute nodes.3— Text node (Node.TEXT_NODE): the text between tags, including whitespace and line breaks.8— Comment node (Node.COMMENT_NODE): an HTML<!-- ... -->comment.9— Document node (Node.DOCUMENT_NODE): thedocumentobject itself, the root of the tree.
Prefer the named constants over the raw numbers — they read better and never change:
const div = document.createElement('div');
div.textContent = 'Hello';
console.log(div.nodeType); // 1
console.log(div.nodeType === Node.ELEMENT_NODE); // true
const textNode = div.firstChild;
console.log(textNode.nodeType === Node.TEXT_NODE); // true<!-- snippet: html-result -->
<div id="example">Example node</div>
<script>
const node = document.getElementById("example");
node.innerHTML = 'Node type is: ' + node.nodeType;
</script>Node names: nodeName vs tagName
Both properties return the name of a node, but they differ in scope:
nodeNameexists on every node. For an element it returns the tag name; for a text node it returns"#text"; for a comment,"#comment"; for the document,"#document".tagNameexists only on elements. On a non-element node it isundefined.
For HTML documents, both return the tag name in uppercase ("DIV", not "div"), regardless of how you wrote the tag:
const div = document.createElement('div');
console.log(div.nodeName); // "DIV"
console.log(div.tagName); // "DIV"
const textNode = document.createTextNode('hi');
console.log(textNode.nodeName); // "#text"
console.log(textNode.tagName); // undefinedRule of thumb: use tagName when you already know you are dealing with an element; use nodeName when you might be inspecting any node type.
<!-- snippet: html-result -->
<div id="example"></div>
<script>
const element = document.getElementById('example');
element.innerHTML = 'nodeName: ' + element.nodeName;
</script>Node contents
There are four properties for reading and writing what is "inside" a node. Choosing the right one matters for correctness, performance, and security.
textContent — plain text, safe
textContent gets or sets the text of a node and all its descendants, ignoring any markup. When you read it, you get the concatenated text with tags stripped. When you write it, the string is inserted as literal text — any < or > is escaped, so it is the safe choice for displaying untrusted data:
const div = document.createElement('div');
div.innerHTML = '<b>Hi</b> there';
console.log(div.textContent); // "Hi there" (tags stripped)
div.textContent = '<script>alert(1)<\/script>';
console.log(div.textContent); // "<script>alert(1)</script>" (inert text, not executed)<!-- snippet: html-result -->
<div id="example"></div>
<script>
const element = document.getElementById('example');
element.textContent = 'Updated text content';
</script>innerHTML — markup inside the element
innerHTML gets or sets the HTML between an element's opening and closing tags. Setting it parses the string as HTML and rebuilds the children:
const div = document.createElement('div');
div.innerHTML = '<p>Para <span>one</span></p>';
console.log(div.innerHTML); // "<p>Para <span>one</span></p>"
console.log(div.children.length); // 1 (the <p>)Security warning: never assign untrusted input to
innerHTML. Because the browser parses it as HTML, a string like<img src=x onerror=alert(1)>becomes a real, script-running element — a classic cross-site-scripting (XSS) hole. UsetextContentfor user-supplied data, or sanitize before inserting.
outerHTML — the element including its own tag
outerHTML is like innerHTML but includes the element's own opening and closing tags. Writing to it replaces the element itself in the DOM, which has a surprising consequence — your variable still points at the old, now-detached node:
const div = document.createElement('div');
div.id = 'box';
div.innerHTML = 'content';
console.log(div.outerHTML); // '<div id="box">content</div>'
// Setting outerHTML replaces the node; `div` is now stale.nodeValue / data — text inside text and comment nodes
For text and comment nodes (which have no innerHTML), use nodeValue or its equivalent data to read and write their content:
const text = document.createTextNode('original');
console.log(text.nodeValue); // "original"
console.log(text.data); // "original"
text.data = 'changed';
console.log(text.nodeValue); // "changed"
// On an element node, nodeValue is null.
const div = document.createElement('div');
console.log(div.nodeValue); // nullWhich one should I use?
| Property | Works on | Reads | Writing parses HTML? | Safe for untrusted input |
|---|---|---|---|---|
textContent | any node | plain text of descendants | no | yes |
innerHTML | elements | inner markup | yes | no (XSS risk) |
outerHTML | elements | element + its tag | yes (replaces node) | no (XSS risk) |
nodeValue / data | text, comment | the node's text | no | yes |
For more on inserting and replacing content, see Modifying the Document.
Conclusion
Reading node properties is the foundation of reliable DOM scripting. Use nodeType (with the Node.* constants) to tell node categories apart, tagName/nodeName to identify tags, and pick a content property deliberately: textContent for safe plain text, innerHTML/outerHTML when you intentionally want to parse markup, and nodeValue/data for bare text and comment nodes. Default to textContent for anything a user typed.