--- id: element-child-content title: Child and Content --- 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` This read-only property on any element returns the **tag name** in uppercase form. This is useful to identify type of an element. Ex. `.tagName` of `
` element is `"DIV"`. ```js someImage.tagName // "IMG" ``` :::note Text nodes don't have `tagName` Text nodes are not elements, 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`. :::     ### 2. parentElement `Node.parentElement: Element | null` This property returns **the parent element** of the current node. If there is no parent, it returns null. The topmost parent element in DOM is `document`. You can use this to check if an element is detached from dom. ```js
child.parentElement //
This is // <- 1. text node // <- 2. element some text // 2.1. text node
``` If you recall, *Element* extends from *Node* - so element and text node are both actually Node. This is important because some properties return **only child elements**, whereas some return **all child nodes** (including text nodes). 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). ::: ### 3. children `Element.children: HTMLCollection` This property returns a live `HTMLCollection` containing all the **child elements** of the node. If there are no child elements, it returns empty HTMLCollection. `HTMLCollection` can be converted to an array using `Array.from()` or `[...ele.children]`. HTMLCollection also 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 }) ``` This property is also available on `Document` and `DocumentFragment`. :::note Counting number of child elements `Element.childElementCount: number` It returns the **number of child elements** of the given element. This is equivalent to `ele.children.length` value. ::: ### 4. childNodes `Node.childNodes: NodeList` This property returns a live `NodeList` containing all the **child nodes** of the current element. If there are no child nodes, it returns a empty NodeList. `NodeList` can be converted to an array easily, using `Array.from()` or `[...node.childNodes]`. NodeList also has a `.length` property. Here, the NodeList is **live** - so the content of NodeList will auto-update. ```jsx
Some text some element and more text
const {childNodes} = parent; childNodes // NodeList [text, span, text] [...childNodes].forEach(node => { // do something }) ``` This property is available on all types of `Node` - like Element, text node, etc. :::note Check if there is any child node `Node.hasChildNodes() : boolean` This method checks whether the given node **has child nodes or not** and returns a boolean value. This is equivalent to checking `node.childNodes.length > 0`. ::: ### 5. firstChild + nextSibling `Element.firstChild: Node` This property returns the element's **first child** node in the tree. If there is no children, it returns `null`. `Element.nextSibling: Node` This property returns the node immediately **after the current one** in their parent's childNodes. ```jsx
let eleA = document.getElementById("A") let eleB = eleA.firstChild //
let eleC = eleB.nextSibling //
eleC.nextSibling // null ``` There is also a similar `previousSibling` property which returns the previous node. Also, there are element-only variants 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) ``` :::   ## Content ### 6. innerText `Element.innerText: string [= value]` Returns the **text content** of the element and its descendants **"as rendered"**. Can be set, to **replace the element's children** with the given string. It creates a *text node* for every normal text range, but replaces each line break with a `
` element. **Example 1 -** `.innerText` tries to return a string which represents the actual visible text, not the text literally written in html. Notice how <br/> tags and the css affects the output - ```jsx Some text
then a newline
and another.
console.log(text.innerText) // SOME TEXT // THEN A NEWLINE // AND ANOTHER. ``` :::note On the other hand, `node.textContent` concatenates the actual text nodes used in the html and returns that string. ```jsx console.log(text.textContent) // Some text then a newlineand another. ``` ::: **Example 2 -** As setter, it replaces `\n` and `\r\n` in the input string with <br/> tags and wraps the rest in text nodes. ```jsx text.innerText = "new text \n and a newline" text.childNodes // NodeList [ // text "new text ", br, text " and a newline." // ] // result html - // new text
and a newline
```     ### 7. innerHTML `Element.innerHTML: string [= value]` Returns the **html markup contained within the element** as a string. Can be set, to replace the **contents of the element with nodes parsed** from the given string. The existing content will be removed. **Example 1-** ```jsx
text1
text2
console.log(parent.innerHTML) //
text1
//
text2
``` **Example 2-** ```jsx
parent.innerHTML = `
text1
text2
` // result html-
text1
text2
``` :::note To remove all children To clear the content of any element, you can use `ele.innerHTML = ""`. ::: ### 8. outerHTML `Element.outerHTML: string [= value]` Returns the html markup of the **element and its contents** as a string. Can be set, to **replace the element** itself with nodes parsed from the given string. **Example 1-** ```jsx
text1
console.log(parent.outerHTML) //
//
text1
//
``` **Example 2-** Replacing `parent2` with 2 new nodes - ```jsx
parent 2
parent 3
parent2.outerHTML = `
child 1
child 2
` // result html-
child 1
child 2
parent 3
```