How to Add an Element to the DOM?

Nowadays, JavaScript frameworks like React or Vue have taken the "pleasure" of managing the DOM (Document Object Model) from most of the developers. So, unless you're a curious person, UI library creator, or someone who doesn't like to over-rely or use frameworks at all, you won't find this blog post useful. ;) But anyway, here are all the ways of adding an element to the DOM directly.

Basics stuff

Creating elements

To create a new HTML element, you have to use the document.createElement() method.

const el = document.createElement("div");

The method takes a string as a tag name for the element (automatically converted to lowercase), and an optional options object, which matters only for Web Components.

Namespaces

You have to know that document.createElement() works only for the HTML elements. This means that elements from a different namespace (most notably SVG-ones) won't work correctly.

To fix that issue, you have to use the document.createElementNS() method, which creates an element with the specified namespace URI.

const svg = document.createElementNS("<http://www.w3.org/2000/svg>", "svg");

Movements

Now, when working with newly-created elements, adding them to the DOM works just like you might expect. But things change when working with elements that are already within DOM, e.g.

/* HTML:
...
<body>
	<div id="app"></div>
</body>
...
*/
const el = document.querySelector("app");

Now, when you'll use one of the methods that we'll talk about in a second on such an element, it won't be added to the DOM, rather than simply moved to the new position.

No matter what parent it had before or how deep it was in the hierarchy, the element will be removed and added back again at the selected position.

Appending

AppendChild

The simplest, most well-known method of appending an element to the DOM is certainly the appendChild().

// ...
document.body.appendChild(el);

The provided element is appended at the end of the parent's children list.

Append/prepend

Now, appendChild() has been around for a long time and is supported by pretty much all the in-use browsers. But, if you're willing to give up some support for the sake of functionality, you might be interested in the newer append() and prepend() methods.

// ...
document.body.append(el);
document.body.prepend(el2);
document.body.append("Text");
/* HTML:
<body>
	<div></div> <- el2
	<div></div> <- el
	Text
</body>
*/

append() appends the element at the end of the parent's children list, while prepend() inserts it at the beginning.

Both append() and prepend() feature the ability to insert strings directly into the DOM. For comparison, to achieve the same effect with appendChild(), you'd have to explicitly create a new Text node:

document.appendChild(document.createTextNode("Text"));

In addition to that, both append() and prepend() can accept multiple arguments and thus, insert multiple nodes at once.

// ...
document.body.append(el, el2);
document.body.appendChild(el);
document.body.appendChild(el2);

Of course, all this goodness comes at a cost. append() and prepend() don't support some older browsers (e.g. no IE) and require (arguably simple) polyfills.

InnerHTML

As you might know, innerHTML is a property, rather than a method. You can either read it or set it to HTML string which, will be parsed as HTML and placed into the DOM.

document.body.innerHTML = "<div>Text</div>";

It seems like a pretty easy and straightforward solution, but it has some major drawbacks:

  • The value returned from the innerHTML property access doesn't have to be the same as the one you've set before, as it's based on the element's content and is generated dynamically.
  • Setting innerHTML removes all previous content of the parent.
  • innerHTML is bad for performance (in most cases), because of the necessity to parse the HTML string and remove all the previous nodes. However, if removing all the children is your goal, then innerHTML = "" is a safe bet.
  • Uncontrolled changes of innerHTML can lead to security issues. Although <script> blocks aren't executed when created with innerHTML, there are other ways of executing possibly malicious JS code without using the <script> block (e.g. inline events listeners)

Inserting

Insert methods, in comparison to append ones, give you more control over where you want to position your element.

InsertBefore

insertBefore() method allows you to insert an element right before the specified one, e.g.

// ...
document.body.append(el);
document.body.insertBefore(el2, el);

The first parameter is the element to be inserted, while the second one is used as a reference. Keep in mind that while the reference should be provided, it can be equal to null, in order to simply append the element at the end of the parent's children list.

While there's no "insertAfter" method or anything like that, you can achieve such an effect through the combination of the insertBefore() method with the nextElementSibling property of the reference node.

// ...
const insertAfter = (parent, child, reference) => {
  parent.insertBefore(child, reference.nextElementSibling);
};

document.body.append(el);
insertAfter(document.body, el2, el);

InsertAdjacent

Next up, we've got a bunch of insertAdjacent methods, which allow you to insert a node in one of the possible positions, in relation to the element the method was called upon (aka target element).

There are 3 of these methods:

All of them have similar syntax, but can be used to insert only one specific kind of content. Take a look at the example of insertAdjacentElement() call:

// ...
document.body.insertAdjacentElement(el, "afterbegin")

The first parameter is the element to be inserted, while the second one is a string indicating the position at which the element is to be inserted. There are 4 available options here:

  • "beforebegin" - just before the target element;
  • "afterbegin" - at the top of the target element's children tree;
  • "beforeend" - at the bottom of the target element's children tree;
  • "afterend" - just after the target element;

Sibling-relative placement

In comparison to all the previous methods, the after() and before() methods rely on the sibling nodes rather than the parent itself. They can insert multiple nodes (elements and text nodes) at once and have support similar to append() or prepend().

// ...
document.body.append(el);
el.after(el2, el3);

Replacement

Lastly, if you want to insert an element in place of a previous one, i.e. replace it, you can use the replaceChild() method, together with providing the new and previous element respectively.

// ...
document.body.append(el);
document.body.replaceChild(el2, el);

There's a lot

So, these are all of the available methods for inserting a new element to the DOM (at least to my knowledge). Again, unless you're a library author or don't want to use any framework except Vanilla JS, then these methods won't matter to you much. However, it's still nice to know at least a little bit about what's going on under-the-hood.

If you like the post consider sharing it and following me on Twitter, Facebook, or through my weekly newsletter. If you're interested, I also recommend checking out my YouTube channel. Again, thanks for reading this piece and have a nice day!