So far you’ve modified existing elements. But often you need to create new ones — render a list of users from an API, add a notification, or build a table from data. This is where document.createElement() comes in.
Several methods for inserting elements, each with a different position:
Copy
const parent = document.querySelector("#container");const newElement = document.createElement("p");newElement.textContent = "New paragraph";// Add to the end (most common)parent.appendChild(newElement);// Add to the beginningparent.prepend(newElement);// Add to the end (modern alternative to appendChild)parent.append(newElement);// Insert before a specific childconst reference = document.querySelector("#reference-element");parent.insertBefore(newElement, reference);// Insert relative to an elementreference.before(newElement); // Before the referencereference.after(newElement); // After the reference
Method
Position
Returns
parent.appendChild(el)
End of parent
The appended element
parent.append(el)
End of parent
undefined
parent.prepend(el)
Start of parent
undefined
el.before(newEl)
Before el
undefined
el.after(newEl)
After el
undefined
append() and prepend() are the modern alternatives. They also accept strings: parent.append("Hello") adds a text node. appendChild only accepts elements.
// Modern — call .remove() on the elementconst card = document.querySelector(".user-card");card.remove();// Older — remove through parentconst parent = card.parentElement;parent.removeChild(card);// Remove all childrenconst container = document.querySelector("#container");container.innerHTML = ""; // Quick way to clear everything
innerHTML with template literals is convenient but vulnerable to XSS if the data contains user input. For data from your own API, it’s fine. For user-generated content, use createElement + textContent.
When adding many elements, each appendChild triggers a page repaint. Use a DocumentFragment to batch insertions:
Copy
const users = await fetch("/api/users").then(r => r.json());const fragment = document.createDocumentFragment();users.forEach(user => { const li = document.createElement("li"); li.textContent = user.name; fragment.appendChild(li); // Add to fragment (no repaint)});document.querySelector("#user-list").appendChild(fragment);// Single repaint when the fragment is added to the DOM
For small lists (under 100 items), the performance difference is negligible. Use fragments when rendering large datasets or when you notice visible flickering during rendering.
React handles creating, updating, and removing DOM elements for you. You describe what the UI should look like; React figures out how to make it happen.
Understanding createElement helps you appreciate what React does under the hood. You won’t use manual DOM creation in React projects, but you’ll understand error messages and debugging better.