Creating, Changing & Removing Elements
Advanced · 20 min read · ▶ live playground · ✦ checkpoint
Finding the right element is only half the job. Real pages need to add a task, update a status, remove a stale row, and do it without turning user text into a security hole.
Change text, not markup
The safest first mutation is textContent. Mutation means changing the live DOM tree after the browser has built it, and textContent writes plain text into an element.
Think of textContent as a label maker. Whatever text you give it becomes ink on the label. It does not become buttons, images, or scripts.
document.createElement("li") creates a new element object that is not on the page yet. append attaches it as the last child of another element. Until the append, the new li is like a note written on your desk: real, editable, but not posted on the board.
That order is useful. Build the element first. Put safe text inside it. Then attach it.
Remove what no longer belongs
remove() detaches an element from the DOM. The object can still exist in a variable, but the page no longer shows it.
The console still knows cancelledOrder.textContent because the variable still points at that element object. The page does not show it because no parent contains it anymore.
The innerHTML trap
innerHTML is different from textContent. HTML parsing means the browser reads a string as markup and creates DOM nodes from it. innerHTML parses markup. So does insertAdjacentHTML.
That is powerful when the string is trusted markup you wrote. It is dangerous when the string came from a user, a URL, a database row, or any outside boundary.
Run this and look at the two boxes. The first box shows the exact characters. The second box turns those characters into a real button with an inline handler, then the demo clicks it so the result is visible without popups or network calls.
There is your rule: text from outside your code goes through textContent. If you need real markup, create elements with createElement and put untrusted words into their textContent.
insertAdjacentHTML(position, markup) belongs on the trusted side of that same line. It parses a markup string and inserts it next to an element without replacing the element itself. Use it for small, fixed snippets your code owns:
The trust boundary is the point. Fixed markup from your own code is one thing. Text from outside your code is another.
Batch with templates and fragments
When you add several similar elements, a <template> gives you inert markup to clone. Inert means the browser parses the template content but does not display it as part of the page.
A DocumentFragment is a lightweight container for DOM nodes that you can build off-screen and append once. Treat it like a serving tray: arrange five cups on the tray, then carry the tray to the table in one trip.
This pattern gives you three wins. The markup shape lives in HTML where it is easy to read. The player data is written with textContent, so names and scores stay text. And the page gets one final append instead of one visible change per row.
That last idea is batching, grouping several DOM changes before attaching them to the page. Small pages survive either way, but batching becomes a habit that keeps bigger interfaces smooth.
You can now find elements, change text, create nodes, remove nodes, and render repeated data safely. Next you will make those changes feel like UI state: classes, inline styles, custom properties, dataset, and measurements from the page.
Checkpoint
Answer all three to mark this lesson complete