Loading...

JavaScript Creating Elements

A kitchen cork board already holds one list item. The list is #board. That item is an li with id milk, and the text is milk. The markup is one line, so the board starts with one element child and no blank text node from a line break. document.createElement("li") builds a new li that is not in the document. parentElement is null, document.body.contains is false, and board.children.length stays 1. textContent = "tea" writes the word on that node and still does not attach it.
board.append(tea) places the item last. The call result is undefined. appendChild would hand the node back; this page uses append. prepend puts bread first. insertBefore(eggs, milk) places eggs immediately before milk, and milk is already a child of the board. The order is bread, eggs, milk, tea. children.length is 4. A side experiment, only on the fresh board, uses createTextNode("salt"). That is a text node, not an li. Appending it leaves children.length at 1, moves childNodes.length from 1 to 2, and nodeType is 3. lastElementChild is still milk. The page demo does not append salt. The line under the board reads bread / eggs / milk / 4. Tea is on the list. It is not in that line. The 4 is the element count. The milk text stays milk. This page sets no CSS property.

New nodes, not a new coat of paint

The previous page wrote style, setProperty, classList, and cssText on a paint chip. It never created a node. The page before that changed words with textContent, innerHTML, and insertAdjacentHTML. This page does not assign style, does not parse an HTML string, and does not rewrite the word milk. getElementById only hands you the board and the milk item. The new rows come from createElement.

Where each new node lands

The board starts as one li: milk. Read the rows in order. The salt row is a side experiment on that fresh board, before tea, bread, and eggs exist. The page demo stops at insertBefore and does not append salt.

📊 Where each new node lands

Call Where the new node sits Element children Easy to mix up
createElement("li") nowhere; parentElement is null still 1, milk the item is already on the board
textContent = "tea" still nowhere still 1 the word itself inserts an li
append(tea) last; the call result is undefined 2: milk, then tea append handing back the node
prepend(bread) first 3: bread, milk, tea swapping prepend with append
insertBefore(eggs, milk) just before milk 4: bread, eggs, milk, tea a reference that is not a child of the board
append(createTextNode("salt")) on the fresh board a text node after milk, not an li still 1 children.length becoming 2

createElement builds the node in memory. The board does not change until a method places that node. children counts element children only. A text node is a child in childNodes, and it is not in children. append and prepend return undefined. appendChild returns the node you passed. append accepts a node or a string; a string becomes a text node. appendChild accepts a node, and a string throws. insertBefore needs a reference that is already a child of that parent. Pass null as the reference and the node goes at the end, the same idea as append. This page passes milk, not null. Appending a node that is already on the board moves it. It does not copy it.

The new li is not on the board yet

The file opens with the one-line list. Nothing has been created. The first logs ask the new node and the board, before any text and before any insert.

Detached item

javascript
let board = document.getElementById("board");
let tea = document.createElement("li");
console.log(tea.parentElement);
console.log(document.body.contains(tea));
console.log(board.children.length);
console.log(tea.textContent);

The logs are null, false, 1, and an empty string. The browser has a real li object. It has no parent. The only element child is still milk. The word milk is that existing item, not the new one.

The word tea still does not insert it

textContent replaces the text inside the node you already hold. It is not an insert method. The board’s child list does not grow.

Text, still detached

javascript
let board = document.getElementById("board");
let tea = document.createElement("li");
tea.textContent = "tea";
console.log(tea.textContent);
console.log(document.body.contains(tea));
console.log(board.children.length);

The logs are tea, false, and 1. You can read the word off the object. The page still shows only milk. Body contains is false because the node has not been placed under the document.

append puts tea last

append adds the node as the last child. The variable fromAppend holds the call result, which is undefined, not the li. After the call, parentElement is the board and the last element text is tea. The order is milk, then tea.

Append tea

javascript
let board = document.getElementById("board");
let tea = document.createElement("li");
tea.textContent = "tea";
let fromAppend = board.append(tea);
console.log(fromAppend);
console.log(tea.parentElement === board);
console.log(board.lastElementChild.textContent);
console.log(board.children.length);

The logs are undefined, true, tea, and 2. appendChild(tea) would have logged the same node as tea. This snippet does not call appendChild. Milk is still the first element child.

prepend and insertBefore set the order

This snippet starts from the original board again, then does three placements. prepend runs after tea is already last, so bread becomes the first child. insertBefore(eggs, milk) uses milk as the reference, so eggs sits between bread and milk. The four texts are bread, eggs, milk, tea.

Place bread and eggs

javascript
let board = document.getElementById("board");
let milk = document.getElementById("milk");
let tea = document.createElement("li");
tea.textContent = "tea";
board.append(tea);
let bread = document.createElement("li");
bread.textContent = "bread";
board.prepend(bread);
let eggs = document.createElement("li");
eggs.textContent = "eggs";
board.insertBefore(eggs, milk);
console.log(board.children[0].textContent);
console.log(board.children[1].textContent);
console.log(board.children[2].textContent);
console.log(board.children[3].textContent);

The logs are bread, eggs, milk, and tea. children.length is 4. Index 1 is eggs, not milk. Milk moved from index 0 to index 2 because two items were placed before it. The milk text is still the word milk.

A text node does not join children

Run this block on the fresh board, the original one-line list, not after the page script. createTextNode builds a text node. nodeType 3 means text. nodeType 1 would mean an element. children ignores it, so the length stays 1. childNodes includes it, so that length goes from 1 to 2. The last element is still the milk item. You may see the word salt in the list, and it is still not an li.

Salt text node

javascript
let board = document.getElementById("board");
let salt = document.createTextNode("salt");
board.append(salt);
console.log(salt.nodeType);
console.log(board.children.length);
console.log(board.childNodes.length);
console.log(board.lastElementChild.id);

The logs are 3, 1, 2, and milk. A string passed to append, such as board.append("salt"), also becomes a text node. It does not become an li. The page demo below does not include this line.

One line under the board

The script sits at the end of the body, after the list exists. It appends tea, prepends bread, and inserts eggs before milk. It does not create salt. It writes index 0, index 1, index 2, and the element count. It does not write the fourth text, tea.

Page demo — cork board

html
<!DOCTYPE html>
<html>
<head>
<title>create elements — page</title>
</head>
<body>
<ul id="board"><li id="milk">milk</li></ul>
<p id="line">…</p>
<script>
let board = document.getElementById("board");
let milk = document.getElementById("milk");
let tea = document.createElement("li");
tea.textContent = "tea";
board.append(tea);
let bread = document.createElement("li");
bread.textContent = "bread";
board.prepend(bread);
let eggs = document.createElement("li");
eggs.textContent = "eggs";
board.insertBefore(eggs, milk);
document.getElementById("line").textContent =
board.children[0].textContent + " / " +
board.children[1].textContent + " / " +
board.children[2].textContent + " / " +
board.children.length;
</script>
</body>
</html>

The line reads bread / eggs / milk / 4. The list itself is bread, eggs, milk, tea. The line stops at the third item and then gives the length, so tea is not the last token and the last token is not a word. Salt is absent. The milk item’s text is still milk. The next page is events. It does not add another way to build these nodes.

Check the board

  1. Create the li and read parentElement, document.body.contains, children.length, and textContent. The values are null, false, 1, and an empty string.
  2. Set the text to tea and read the text, document.body.contains, and children.length. The values are tea, false, and 1.
  3. Append tea and read the call result, whether the parent is the board, the last element text, and the length. The values are undefined, true, tea, and 2. Then run the order snippet and read bread, eggs, milk, tea.
  4. On the fresh board, append the salt text node and read nodeType, children.length, childNodes.length, and the last element id. The values are 3, 1, 2, and milk. Read the page line: bread / eggs / milk / 4.

Misses on this board

The list still opens with milk. The call used the wrong kind of insert.

  • Expecting createElement("li") to show tea on the board immediately
  • Expecting textContent = "tea" to raise children.length
  • Expecting append to return the li; that return is what appendChild does
  • Passing a string to appendChild; a string belongs to append, where it becomes a text node
  • Calling insertBefore with a reference that is not a child of the board
  • Counting the salt text node inside children
  • Building the new row with innerHTML; the changing-html page parsed markup
  • Setting style.color here; the previous page wrote CSS
  • Reading the line as bread / eggs / milk / tea
  • Calling remove or cloneNode here; this page only adds the three items

Leave with this

  • createElement("li") builds a detached item, so parentElement is null and children.length stays 1
  • textContent = "tea" writes the word and still leaves the node off the board
  • append(tea) puts tea last, and the call result is undefined
  • prepend(bread) and insertBefore(eggs, milk) produce the order bread, eggs, milk, tea
  • createTextNode("salt") on the fresh board leaves children.length at 1 and reports nodeType 3
  • The line reads bread / eggs / milk / 4, and the milk text stays milk

🧠 Test Your Knowledge

Ready to Start

Test Your Knowledge

Challenge yourself with this interactive quiz and see how well you understand the topic

❓
8
Questions
🎯
70%
To Pass
♾️
∞
Time
🔄
∞
Attempts

📝 Instructions

  • Read each question carefully
  • Select the best answer for each question
  • You can retake the quiz as many times as you want
  • Your progress will be shown at the top