Creating, Removing and Traversing Elements

Build page content from data with createElement, append, prepend and template elements, remove and replace elements, and move around the DOM tree with parent, children and siblings.

Lesson 35 of 56Intermediate15 min read

Most interactive pages build part of their content with JavaScript. A to-do app adds a list item when you press Enter. A shop renders product cards from data sent by a server. A chat window appends each new message. Comment sections, notifications, search results and table rows all appear on the page without a reload, because JavaScript creates elements and inserts them into the DOM.

In the DOM manipulation lesson you changed the text, classes and styles of elements that were already in the HTML. This lesson goes further: creating brand new elements, putting them exactly where you want, removing or replacing them, and building whole lists from arrays of data.

You'll also learn DOM traversal: moving from one element to its parent, children or neighbours. That's essential when a click on a "Delete" button needs to find and remove the card it belongs to. And you'll learn how to insert content safely, so text typed by users can never inject harmful HTML into your page.

Creating and inserting elements

JavaScript
const li = document.createElement("li");
li.textContent = "Buy milk";
li.className = "task";
document.querySelector("#list").append(li);
MethodPuts the new content…
parent.append(a, b)At the end, inside the parent (accepts elements and text)
parent.prepend(a)At the start, inside the parent
el.before(a)Just before el, as a sibling
el.after(a)Just after el, as a sibling
el.replaceWith(a)In place of el
parent.appendChild(a)At the end (older method, one element only)

An element can only be in one place at a time: appending an element that's already on the page moves it.

Removing and copying

  • el.remove() takes an element out of the page.
  • parent.replaceChildren() with no arguments empties the parent; with arguments it swaps in new children.
  • el.cloneNode(true) copies an element and everything inside it (but not its event listeners).
  • el.hidden = true hides without removing, if you'll show it again soon.

Removing an element also removes its children. Any event listeners on removed elements are cleaned up once nothing else refers to them.

Building from data safely

ApproachGood forWatch out
createElement + textContentAnything with user dataMore lines of code
insertAdjacentHTML("beforeend", html)Quick markup from trusted stringsNever put user input in the string
innerHTML = htmlReplacing a whole area at onceDestroys existing elements and listeners; same safety rule
<template> + content.cloneNode(true)Repeated componentsFill in values with textContent

textContent always treats data as plain text, so a comment containing <script> or <img onerror=...> is shown harmlessly instead of running. This protects against cross-site scripting (XSS), one of the most common web security problems.

Traversing the DOM

Property or methodFinds
el.parentElementThe parent element
el.childrenChild elements (a live collection)
el.firstElementChild, el.lastElementChildFirst and last child elements
el.nextElementSibling, el.previousElementSiblingNeighbours
el.closest(".card")The nearest ancestor (or itself) matching a selector
el.querySelector(".price")The first matching descendant
el.contains(other)Whether other is inside el

closest is the star: from a clicked button, event.target.closest("li") finds the list item it belongs to, however deeply the button is nested.

JavaScript Create Elements Syntax

Creating and traversing

const card = document.createElement("article");
card.className = "card";
card.textContent = product.name;
grid.append(card);

card.remove();
oldEl.replaceWith(newEl);
list.replaceChildren(...items);

btn.closest(".card");
card.parentElement; card.children; card.nextElementSibling;

JavaScript Create Elements Summary

  • document.createElement makes an element; append, prepend, before and after insert it.
  • remove, replaceWith and replaceChildren take elements out or swap them.
  • Use textContent for user data to prevent XSS; avoid putting user input in innerHTML.
  • <template> elements hold reusable markup that you clone and fill.
  • closest, parentElement, children and the sibling properties move around the DOM tree.

JavaScript Create Elements Examples

Each example runs in the page. Edit the code and press Run to see what changes.

Example 1

A to-do list built with createElement

Type a task and press Add. Click a task to remove it.

const form = document.querySelector("#add");
const input = document.querySelector("#task");
const list = document.querySelector("#list");
const empty = document.querySelector("#empty");

form.addEventListener("submit", (e) => {
  e.preventDefault();
  const li = document.createElement("li");
  li.textContent = input.value;
  li.title = "Click to remove";
  li.addEventListener("click", () => {
    li.remove();
    empty.hidden = list.children.length > 0;
  });
  list.append(li);
  empty.hidden = true;
  input.value = "";
  input.focus();
});
ResultEdit the code, then press Run or Ctrl+Enter
Line-by-line explanation
  1. Line 7Stop the form reloading the page.
  2. Lines 8 to 9Create a list item and set its text safely.
  3. Lines 11 to 14Clicking the item removes it, and the "empty" message returns when the list is empty.
  4. Line 15Insert the new item at the end of the list.
Example 2

Rendering cards from data with a template

const products = [
  { name: "Desk lamp", price: 24 },
  { name: "Notebook <b>A5</b>", price: 6.5 },
  { name: "Mug", price: 9 },
];

const tpl = document.querySelector("#card-tpl");
const grid = document.querySelector("#grid");

const cards = products.map((p) => {
  const card = tpl.content.cloneNode(true);
  card.querySelector(".name").textContent = p.name;
  card.querySelector(".price").textContent = `£${p.price.toFixed(2)}`;
  return card;
});
grid.append(...cards);

grid.addEventListener("click", (e) => {
  if (e.target.matches(".remove")) e.target.closest(".card").remove();
});
ResultEdit the code, then press Run or Ctrl+Enter
Line-by-line explanation
  1. Line 3Data containing HTML tags is shown as plain text, not run as HTML.
  2. Lines 10 to 15Clone the template for each product and fill in its text.
  3. Line 16Insert all the cards in one go.
  4. Lines 18 to 20One listener on the grid finds the clicked card with closest and removes it.
Example 3

Moving around the DOM tree

const bake = document.querySelector("#bake");
const btn = bake.querySelector("button");

console.log("Parent:", bake.parentElement.id);
console.log("Previous:", bake.previousElementSibling.textContent);
console.log("Next:", bake.nextElementSibling.textContent);
console.log("Children of list:", bake.parentElement.children.length);
console.log("closest li:", btn.closest("li").id);

const note = document.createElement("li");
note.textContent = "Preheat oven";
bake.before(note);
bake.parentElement.lastElementChild.after(Object.assign(document.createElement("li"), { textContent: "Serve" }));
console.log([...document.querySelector("#steps").children].map(li => li.firstChild.textContent.trim()));
ResultEdit the code, then press Run or Ctrl+Enter
Line-by-line explanation
  1. Lines 4 to 7Move up to the parent and sideways to the neighbours.
  2. Line 8From the button, closest climbs up to its list item.
  3. Line 12Insert a new step just before "Bake".
  4. Line 13Add a final step after the last one.

Common JavaScript Create Elements Mistakes

Putting user input into innerHTML

Don't
comments.innerHTML += `<li>${userComment}</li>`; // can run injected HTML
Do
const li = document.createElement("li");
li.textContent = userComment;
comments.append(li);

Adding elements one by one in a loop

Don't
for (const item of items) list.innerHTML += `<li>${item}</li>`; // rebuilds the list every time
Do
list.append(...items.map(item => Object.assign(document.createElement("li"), { textContent: item })));

Using parentNode chains

Don't
btn.parentNode.parentNode.parentNode.remove(); // breaks when the HTML changes
Do
btn.closest(".card").remove();

JavaScript Create Elements in Real Projects

Creating elements in real apps

Infinite-scroll feeds append new posts as you reach the bottom. Shopping baskets add and remove rows as you change your order. Notification systems create a toast element, insert it, then remove it after a few seconds. Frameworks like React and Vue do all of this for you behind the scenes, but they're built on exactly these DOM methods.

JavaScript Create Elements Exercises

Answer each one and check it instantly. If you get stuck, open the hint before the answer.

Fill in the blankseasy

Create a paragraph element and add it to the body.

const p = document.("p");
p.textContent = "Hello";
document.body.(p);
Predict the outputmedium

What is logged?

const ul = document.createElement("ul");
const a = document.createElement("li");
const b = document.createElement("li");
ul.append(a, b);
ul.prepend(b);
console.log(ul.children.length, ul.firstElementChild === b);
Multiple choiceeasy

Which removes an element from the page?

Multiple choicemedium

Why use textContent instead of innerHTML for user data?

Fix the bugmedium

addRow(name) should add a new <li> with the name as text to the end of #people, and each row's button should remove only its own row. Fix it.

function addRow(name) {
  const li = document.createElement("li");
  li.innerHTML = name + ' <button>x</button>';
  document.querySelector("#people").prepend(li);
  li.querySelector("button").addEventListener("click", () => {
    document.querySelector("#people").remove();
  });
}
addRow("Ana");
addRow("<b>Ben</b>");
ResultEdit the code, then press Run or Ctrl+Enter
Checks
  • Rows are added at the end
  • Names are text, not HTML
  • A button removes only its row

JavaScript Create Elements Quiz

5 questions to check what you learned.

  1. Which method adds content at the start of a parent?

    • prepend
    • append
    • before
    • after
  2. What does el.closest(".card") return?

    • The next .card on the page
    • The nearest ancestor (or el itself) matching .card
    • All .card children
    • The first .card in the document
  3. What happens if you append an element that's already on the page?

    • It's copied
    • An error
    • Nothing
    • It moves to the new place
  4. What is a template element for?

    • Styling forms
    • Loading scripts
    • Defining CSS variables
    • Holding inert markup you can clone and fill with JavaScript
  5. Why insert many elements with one append(...items) call?

    • append only accepts arrays
    • One insertion means one layout update instead of many
    • It removes duplicates
    • It makes elements focusable

JavaScript Create Elements Challenge

Render a scoreboard

Write renderScores(scores) where scores is an array like [{ name: "Mia", points: 12 }]:

  1. Empty #board first (so calling it twice doesn't duplicate rows)
  2. Sort a copy of the scores from highest to lowest points
  3. For each score, create an <li> whose text is `${name}: ${points}`, using textContent
  4. Give the first (top) <li> the class leader
  5. Append all the items to #board
function renderScores(scores) {

}

renderScores([{ name: "Mia", points: 12 }, { name: "Raj", points: 30 }, { name: "Lee", points: 18 }]);
ResultEdit the code, then press Run or Ctrl+Enter
Checks
  • Rows are sorted highest first
  • Leader is marked
  • Calling again doesn't duplicate
  • Names are added as text