---
id: create-modify-element
# sidebar_label: DOM Manipulation
title: DOM Manipulation
slug: /
---

import Admonition from "../components/Admonition"
import Accordion from "../components/Accordion"
import MDN from "../components/MDNBadge"

## Finding elements

### 1. querySelector()

This method returns the **first element that matches the CSS selector**. If no match is found, it returns `null`.

```js
document.querySelector(selector);

// <div className="box" />
document.querySelector(".box"); // returns .box
document.querySelector(".not-found"); // null
```

<Accordion>
  <Admonition type="note" title="Extra">
  This method is also available on all DOM nodes. If you want to look within a specific element, this is very useful.

  ```js
  // Example - .outer > .inner
  outerEle.addEventListener((ev) => {
    var innerEle = ev.target.querySelector(".inner");
  });
  ```
  </Admonition>
</Accordion>

<MDN title="querySelector" url="https://developer.mozilla.org/en-US/docs/Web/API/Element/querySelector" />

### 2. querySelectorAll()

This method returns **all the elements that match** the specified CSS selector.

It returns a **static NodeList**, which contains the matching elements. If no match is found, it returns empty NodeList.

:::note How to consume NodeList?  
 NodeList is a iterable, so it can be iterated using `for..of` loop, or converted to a array using spread syntax like `[...nodelist]`.

Here, the NodeList is static - meaning any changes in the DOM later does not affect the content of the existing collection. More about NodeList [here](https://developer.mozilla.org/en-US/docs/Web/API/NodeList).  
:::

```js
var paras = document.querySelectorAll("p");

for (var p of paras) {
  p.className = "note";
}
```

<MDN title="querySelectorAll" url="https://developer.mozilla.org/en-US/docs/Web/API/Element/querySelectorAll" />

## Create / insert element

### 1. createElement()

It creates a new HTML element, taking the tag name (`"div"`) as argument.

```js
document.createElement("div")
// creates <div/>
```

<Accordion title="Related">
  <Admonition type="note" title="Creating text node">
    To add some text inside a element, you'll need to create a <b>text node</b>. 
    `createTextNode` method takes a string as input and returns a new TextNode.

  ```js
  var ele = document.createElement("div")
  var newText = document.createTextNode("Hello world")

  ele.appendChild(newText) 
  // <div>Hello world</div>
  ```
  </Admonition>
</Accordion>

<MDN title="createElement" url="https://developer.mozilla.org/en-US/docs/Web/API/Document/createElement" />

### 2. setAttribute()

It sets a attribute on the current element. 

`Element.setAttribute(name, value)`

`name` - name of the attribute to add. Ex- "type".  
`value` - value of the attribute. Ex- "text".

```js
var ele = document.createElement("input")

ele.setAttribute("type", "text") 
// <input type="text"/>
```
<MDN title="setAttribute" url="https://developer.mozilla.org/en-US/docs/Web/API/Element/setAttribute" />


### 3. appendChild()

It inserts a new element as the last child of the parent element.

`Element.appendChild(newElement)`

```js
var eleDiv = document.createElement("div")
var eleH1 = document.createElement("h1")

eleDiv.appendChild(eleH1)
// <div><h1></h1></div>
```

<Accordion title="Edge cases and alternative">
  <Admonition type="note" title="If it already has a parent">
  If newElement is already a child of another element, 
  then it is removed from its existing parent and then added to the new parent.
  </Admonition>

  <Admonition type="note" title="If it is DocumentFragment">
  If newElement is a DocumentFragment, then - instead of adding the fragment itself as a child, 
  the entire content of the fragment is added as children of the parent element.
  </Admonition>

  <Admonition type="note" title=".append()">
  There is a newer api called .append(), which is a superset of .appendChild().<br/><br/>

  ⭐️ .append() allows you to insert multiple child elements in a single call. It also allows string as input, which gets converted to Text node.  

  ```js
  ele1.append(ele2, ele3, 'hello world')
  ```

  💔 .appendChild() only allows inserting a single element at a time.
  </Admonition>
</Accordion>

<MDN title="appendChild" url="https://developer.mozilla.org/en-US/docs/Web/API/Node/appendChild" />

### 4. removeChild()

`Element.removeChild(childElement)`

This method tries to remove a child element from the parent and returns the removed node.

If the element to be removed is not a child of the parent element, it throws a `NotFoundError` DOMException.

```js
// <div class="parent">
//   <div class="child"/>
// </div>

parentEle.removeChild(childEle)
```

<MDN title="removeChild" url="https://developer.mozilla.org/en-US/docs/Web/API/Node/removeChild" />

### 5. insertBefore()

`Element.insertBefore(newEle, refEle)`

This method inserts a new child element before another child within a parent.

`newEle` - The node to be inserted.  

`refEle` - The reference element before which newEle should be inserted. If refEle is `null`, then newEle is added as the last child.

```js
// <ul>
//   <li> Apple </li>
//   <li> Zebra </li>
// </ul>

// To add a new <li> above "Zebra"

var parent = document.querySelector("ul")
var ref = document.querySelector("li:last-child")

var newEle = document.createElement("li")

parent.insertBefore(newEle, ref)
```

:::note insertAfter()
There is no `insertAfter()` method. It can be emulated by combining insertBefore method with ele.nextSibling.

```js
parent.insertBefore(newEle, ref.nextSibling)
```
:::

<MDN title="insertBefore" url="https://developer.mozilla.org/en-US/docs/Web/API/Node/insertBefore" />

### 6. Document Fragment

DocumentFragment can be considered to be a off-canvas lightweight `document` object. 
It is generally used for batching multiple operations - by doing them over time in the fragment and rendering it in one shot to the actual visible DOM.

Because it is not rendered, making changes to the fragment doesn't cause any performance impact (no reflow).

**Methods** -

`document.createDocumentFragment()` - creates a new empty fragment.

`.appendChild()` / `.insertBefore()` - can be used to move the whole content of the fragment to the actual DOM.

**Example** -

```js
var fragment = document.createDocumentFragment()

// Insert / modify elements in fragment

// in dom, <div class="outer"/>

outerEle.appendChild(fragment)
// This will remove all content from fragment and 
// insert them within outerEle.

```

<MDN title="Document Fragment" url="https://developer.mozilla.org/en-US/docs/Web/API/DocumentFragment" />