# Node properties: type, tag and contents Let's get a more in-depth look at DOM nodes. In this chapter we'll see more into what they are and their most used properties. [cut] ## DOM node classes DOM nodes have different properties depending on their class. For instance, element nodes corresponding to tag `` have link-related properties, and those corresponding to `` have input-related and so on. Text nodes are not the same as element nodes: they have properties of their own. But there are also common properties and methods between all of them, because of the inheritance. Each DOM node belongs to the corresponding built-in class. These classes form a hierarchy. The root is [EventTarget](https://dom.spec.whatwg.org/#eventtarget), that is inherited by [Node](http://dom.spec.whatwg.org/#interface-node), and other DOM nodes inherit from it. Here's the picture, explanations to follow: ![](dom-class-hierarchy.png) The classes are: - [EventTarget](https://dom.spec.whatwg.org/#eventtarget) is the root "abstract" class. Objects of that class are never created. It serves as a base, so that all DOM nodes support so-called "events", we'll study them later. - [Node](http://dom.spec.whatwg.org/#interface-node) is also an "abstract" class, serving as a base for DOM nodes. It provides the core tree functionality: `parentNode`, `nextSibling`, `childNodes` and so on (they are getters). Objects of `Node` class are never created. But there are concrete node classes that inherit from it, namely: `Text` for text nodes, `Element` for element nodes and more exotic ones like `Comment` for comment nodes. - [Element](http://dom.spec.whatwg.org/#interface-element) is a base class for DOM elements. It provides element-level navigation like `nextElementSibling`, `children` and searching methods like `getElementsByTagName`, `querySelector`. In the browser there may be not only HTML, but also XML and SVG documents. The `Element` class serves as a base for more specific classes: `SVGElement`, `XMLElement` and `HTMLElement`. - [HTMLElement](https://html.spec.whatwg.org/multipage/dom.html#htmlelement) is finally the basic class for all HTML elements. It is inherited by various HTML elements: - [HTMLInputElement](https://html.spec.whatwg.org/multipage/forms.html#htmlinputelement) -- the class for `` elements, - [HTMLBodyElement](https://html.spec.whatwg.org/multipage/semantics.html#htmlbodyelement) -- the class for `` elements, - [HTMLAnchorElement](https://html.spec.whatwg.org/multipage/semantics.html#htmlanchorelement) -- the class for `` elements - ...and so on, each tag has its own class that may provide specific properties and methods. So, the full set of properties and methods of a given node comes as the result of the inheritance. For instance, `` element is of the [HTMLInputElement](https://html.spec.whatwg.org/multipage/forms.html#htmlinputelement) class: - `HTMLInputElement` itself provides input-specific properties. - It inherits the common HTML element methods (and getters/setters) from `HTMLElement` class. - Then it supports common element methods, because `HTMLElement` inherits from `Element`. - Then it supports common DOM node properties, because it inherits from `Node`. - Finally, it supports events (to be covered), because it inherits from `EventTarget`. - (and for completeness: `EventTarget` inherits from `Object`) To see the DOM node class name, we can remember that an object usually has the `constructor` property. It references to the class constructor, so the `constructor.name` is what we need: ```js run alert( document.body.constructor.name ); // HTMLBodyElement ``` ...Or we can just `toString` it: ```js run alert( document.body ); // [object HTMLBodyElement] ``` We also can use `instanceof` to check the inheritance chain: ```js run alert( document.body instanceof HTMLBodyElement ); // true alert( document.body instanceof HTMLElement ); // true alert( document.body instanceof Element ); // true alert( document.body instanceof Node ); // true alert( document.body instanceof EventTarget ); // true ``` As we can see, DOM nodes are regular JavaScript objects. They use prototype-based classes for inheritance. That's easy to see by outputting an element with `console.dir(elem)`. There you can see `HTMLElement.prototype`, `Element.prototype` and so on. ```smart header="`console.dir(elem)` versus `console.log(elem)`" Most browsers support two commands in their developer tools: `console.log` and `console.dir`. They output their arguments to the console. For JavaScript objects these commands usually do the same. But for DOM elements they are different: - `console.log(elem)` shows the element DOM tree. - `console.dir(elem)` shows the element as a DOM object, good to explore its properties. Try it on `document.body`. ``` ````smart header="IDL in the spec" In the specification classes are described using not JavaScript, but a special [Interface description language](https://en.wikipedia.org/wiki/Interface_description_language) (IDL), that is usually easy to understand. The most important difference is that all properties are given with their types. For instance, `DOMString`, `boolean` and so on. Here's an excerpt from it, with comments: ```js // Define HTMLInputElement *!* // The colon means that it inherits from HTMLElement */!* interface HTMLInputElement: HTMLElement { *!* // "DOMString" means that the property is a string */!* attribute DOMString accept; attribute DOMString alt; attribute DOMString autocomplete; attribute DOMString value; *!* // boolean property (true/false) attribute boolean autofocus; */!* ... *!* // now the method: "void" means that that returns no value */!* void select(); ... } ``` Other classes are somewhat similar. ```` ## The "nodeType" property The `nodeType` property provides an old-fashioned way to get the "type" of a DOM node. It has a numeric value: - `elem.nodeType == 1` for element nodes, - `elem.nodeType == 3` for text nodes, - `elem.nodeType == 9` for the document object, - there are few other values in [the specification](https://dom.spec.whatwg.org/#node). For instance: ```html run ``` In modern scripts, we can use `instanceof` and other class-based tests to see the node type, but sometimes `nodeType` may be simpler. We can only read `nodeType`, not change it. ## Tag: nodeName and tagName Given a DOM node, we can read its tag name from `nodeName` or `tagName` properties: For instance: ```js run alert( document.body.nodeName ); // BODY alert( document.body.tagName ); // BODY ``` Is there any difference between tagName and nodeName? Actually, yes, the difference is reflected in their names, but is indeed a bit subtle. - The `tagName` property exists only for `Element` nodes. - The `nodeName` is defined for any `Node`: - for elements it means the same as `tagName`. - for other node types (text, comment etc) it has a string with the node type. So `tagName` can only be used for elements, while `nodeName` can say something about other node types. For instance let's compare `tagName` and `nodeName` for the `document` and a comment node: ```html run ``` If we only deal with elements, then `tagName` is the only thing we should use. ```smart header="The tag name is always uppercase except XHTML" The browser has two modes of processing documents: HTML and XML. Usually the HTML-mode is used for webpages. XML-mode is enabled when the browser receives an XML-document with the header: `Content-Type: application/xml+xhtml`. In HTML mode `tagName/nodeName` is always uppercased: it's `BODY` either for `` or ``. In XML mode the case is kept "as is", but it's rarely used. ``` ## innerHTML: the contents The [innerHTML](https://w3c.github.io/DOM-Parsing/#widl-Element-innerHTML) property allows to get the HTML inside the element as a string. We can also modify it. So it's one of most powerful ways to change the page. The example shows the contents of `document.body` and then replaces it completely: ```html run

A paragraph

A div
``` We can try to insert an invalid HTML, the browser will fix our errors: ```html run ``` ```smart header="Scripts don't execute" If `innerHTML` inserts a ` ``` Unlike `innerHTML`, writing to `outerHTML` does not change the element. Instead, it replaces it as a whole in the outer context. Yeah, sounds strange, and strange it is. Take a look. Consider the example: ```html run
Hello, world!
``` In the line `(*)` we take the full HTML of `
...
` and replace it by `

...

`. In the outer document we can see the new content instead of the `
`. But the old `div` variable is still the same. The `outerHTML` assignment does not modify the DOM element, but extracts it from the outer context and inserts a new piece of HTML instead of it. Novice developers sometimes make an error here: they modify `div.outerHTML` and then continue to work with `div` as if it had the new content in it. That's possible with `innerHTML`, but not with `outerHTML`. We can write to `outerHTML`, but should keep in mind that it doesn't change the element we're writing to. It creates the new content on its place instead. We can get a reference to new elements by querying DOM. ## nodeValue/data: text node content The `innerHTML` property is only valid for element nodes. Other node types have their counterpart: `nodeValue` and `data` properties. These two are almost the same for practical use, there are only minor specification differences. So we'll use `data`, because it's shorter. We can read it, like this: ```html run height="50" Hello ``` For text nodes we can imagine a reason to read or modify them, but why comments? Usually, they are not interesting at all, but sometimes developers embed information into HTML in them, like this: ```html
Welcome, Admin!
``` ...Then JavaScript can read it and process embedded instructions. ## textContent: pure text The `textContent` provides access to the *text* inside the element: only text, minus all ``. For instance: ```html run

Headline!

Martians attack people!

``` As we can see, only text is returned, as if all `` were cut out, but the text in them remained. In practice, reading such text is rarely needed. **Writing to `textContent` is much more useful, because it allows to write text the "safe way".** Let's say we have an arbitrary string, for instance entered by a user, and want to show it. - With `innerHTML` we'll have it inserted "as HTML", with all HTML tags. - With `textContent` we'll have it inserted "as text", all symbols are treated literally. Compare the two: ```html run
``` 1. The first `
` gets the name "as HTML": all tags become tags, so we see the bold name. 2. The second `
` gets the name "as text", so we literally see `Winnie-the-pooh!`. In most cases, we expect the text from a user, and want to treat it as text. We don't want unexpected HTML in our site. An assignment to `textContent` does exactly that. ## The "hidden" property The "hidden" attribute and the DOM property specifies whether the element is visible or not. We can use it in HTML or assign using JavaScript, like this: ```html run height="80"
Both divs below are hidden
JavaScript assigned the property "hidden"
``` Technically, `hidden` works the same as `style="display:none"`. But it's shorter to write. Here's a blinking element: ```html run height=50
A blinking element
``` ## More properties DOM elements also have additional properties, many of them provided by the class: - `value` -- the value for ``, `