---
id: element-properties
title: Element attributes and properties
---
import Admonition from "../components/Admonition"
import Accordion from "../components/Accordion"
import InternalLink from "../components/InternalLink"
import MDN from "../components/MDNBadge"
### 1. tagName
`Element.tagName : string`
`.tagName` is a read-only property on any element, which returns the tag name in uppercase form. This is useful to identify type of a element.
Ex. For a `
` element, tagName is `"DIV"`.
```js
ele = document.querySelector("img");
ele.tagName // "IMG"
```
:::note Text nodes don't have `tagName`
Text nodes are not element, so they don't have any tagName. To identify the type of node, use `.nodeType` property. For text nodes, `nodeType` is `3` - same as the constant `Node.TEXT_NODE`.
:::
## Children
:::note Types of Children
All elements will *generally* have 2 types of children - 1. element and 2. text node.
You can think of elements as other tags and text node as the text within a tag.
```jsx
This is // <- 1. text node
// <- 2. element
some text // 2.1. contains text node
```
If you recall, *Element* extends from *Node* - so all elements are nodes. That means, every child is technically a node.
This is important because some properties return **only child elements**, whereas others return **all child nodes** (both element and text node). For ex, `ele.childNodes` returns all child nodes, but `ele.children` returns only child elements.
**Always use the one which is more suitable for your case**. Remember, even if you haven't added any "text" between a tag, it can still have **invisible text nodes** due to spaces and newline characters.
```jsx
container.childNodes // [text, div, text]
// extra text nodes contain newline and space
```
Read more about [other types of nodes](https://developer.mozilla.org/en-US/docs/Web/API/Node/nodeType) and how [whitespace works in html](https://developer.mozilla.org/en-US/docs/Web/API/Document_Object_Model/Whitespace).
:::
### 2. children
`Element.children: HTMLCollection`
This read-only property returns a live `HTMLCollection` containing all the **child elements** of the node. If there are no child elements, it returns empty HTMLCollection.
This property is available on `Document`, `Element`, and `DocumentFragment`, but not on text node.
`HTMLCollection` can be consumed easily by converting it to an array, using `Array.from()` or `[...ele.children]`. HTMLCollection is also a iterable and has a `.length` property.
Here, the HTMLCollection is **live** - meaning if new child elements are added, they will automatically appear in this collection.
```jsx
Some text
some element
const children = parent.children;
children // HTMLCollection [span]
// 1. For-loop using .length
for (let i = 0; i < children.length; i++) {
console.log(children[i].tagName);
}
// 2. Convert to array
[...children].forEach(ele => {
// do something
})
```
### 3. childNodes
`Element.childNodes: NodeList`
This read-only property returns a live `NodeList` containing all the **child nodes** of the current element, including text nodes. If there are no child nodes, it returns a empty NodeList.
This property is available on all types of `Node` - like Element, text node, etc.
`NodeList` can be converted to an array easily, using `Array.from()` or `[...ele.children]`. NodeList is also a iterable and has a `.length` property.
Here, the NodeList is **live**.
```jsx
Some text
some element
and more text
const childNodes = parent.childNodes;
childNodes // NodeList [text, span, text]
[...childNodes].forEach(node => {
// do something
})
```
### 4. firstChild + nextSibling
`Element.firstChild: Node`
This property returns the element's **first child** node in the tree. If the node has no children, then it returns `null`.
`Element.nextSibling: Node`
This property returns the node immediately **after the current one** in their parent's childNodes.
```jsx
var eleA = document.getElementByID("A")
var eleB = eleA.firstChild //
var eleC = eleB.nextSibling //
eleC.nextSibling // null
```
There is also a similar `previousSibling` property, which returns the previous node. Also, there are element-only variant for all these properties like `firstElementChild`, `nextElementSibling`, etc.
:::note Easier traversal
This allows accessing the DOM tree in [Left-child right-sibling](https://en.wikipedia.org/wiki/Left-child_right-sibling_binary_tree) (LCRS) form, which is more memory efficient for usual traversal.
#### How do you implement **dom traversal**?
The typical approach is to use a queue, push all children to the queue, pop them one-by-one and visit them. This requires **extra memory** because of the queue data structure which holds all the *next items to visit*.
But with the LCRS form, you always have access to the next item **without using extra space**. If current element has child, visit `.firstChild`. Then visit next node using `.nextSibling`.
```js
// 1. Typical approach
var queue = [root]
while (queue.length > 0) {
const item = queue.shift();
console.log(item);
if (item.hasChildNodes()) {
queue = Array.from(item.childNodes).concat(queue)
}
}
// 2. LCRS approach
function traverse(item) {
if (item === null) {
return;
}
console.log(item);
traverse(item.firstChild)
traverse(item.nextSibling)
}
traverse(root.firstChild)
```
:::