Curriculum Series

Adding, removing, and mutating DOM elements in vanilla JS

Adding, removing, and mutating DOM elements in vanilla JS

Adding, removing, and mutating DOM elements in vanilla JS

JavaScript

TL;DR

The DOM gives you a small set of primitives: createElement to build nodes, append/appendChild to insert them, remove/removeChild to take them out, and a handful of APIs to change content and attributes. Master these and you can make any page dynamic without a framework.

Creating and inserting

javascript
// Create a new element
const paragraph = document.createElement('p');
paragraph.textContent = 'Hello, world!';
paragraph.className = 'greeting';
// Add it to the page
document.body.appendChild(paragraph);

Insertion alternatives worth knowing:

javascript
const container = document.querySelector('#container');
// append — adds to the end (can add multiple items and text)
container.append(element1, element2, 'some text');
// prepend — adds to the beginning
container.prepend(element);
// before / after — adds next to the element
existingElement.before(newElement);
existingElement.after(newElement);
// insertAdjacentHTML — inserts HTML string at a specific position
container.insertAdjacentHTML(
'beforeend',
'<p>New paragraph</p>'
);

append/prepend are the modern go-tos — they accept multiple nodes and raw strings, unlike the older appendChild.

Removing

javascript
// Modern way — call remove() on the element
const element = document.querySelector('#old-item');
element.remove();
// Older way — remove through the parent
const parent = document.querySelector('#list');
const child = document.querySelector('#old-item');
parent.removeChild(child);

Mutating

Content:

javascript
element.textContent = 'New text'; // safe, plain text
element.innerHTML = '<strong>Bold</strong>'; // parses HTML

Reach for textContent by default — innerHTML with untrusted input is an XSS vector.

Attributes:

javascript
element.setAttribute('data-id', '42');
element.getAttribute('data-id'); // "42"
element.removeAttribute('data-id');
// Or use properties directly
element.id = 'my-element';
element.className = 'active';

Inline styles:

javascript
element.style.color = 'red';
element.style.fontSize = '16px';
element.style.display = 'none';

Classes (prefer this over mashing className strings):

javascript
element.classList.add('active');
element.classList.remove('active');
element.classList.toggle('active');
element.classList.contains('active'); // true/false

Swapping elements

javascript
const oldElement = document.querySelector('#old');
const newElement = document.createElement('div');
newElement.textContent = 'I am new';
oldElement.replaceWith(newElement);

Cloning

javascript
const original = document.querySelector('.card');
// Shallow clone (no children)
const clone = original.cloneNode(false);
// Deep clone (includes all children)
const deepClone = original.cloneNode(true);
document.body.appendChild(deepClone);

Interview Tip

Show you know both the modern and legacy APIs — append/remove/replaceWith alongside the older appendChild/removeChild. Reaching for classList rather than hand-editing className is a small signal that you've done this at scale.

Why interviewers ask this

Even in a React-first world, every senior frontend engineer should be able to drop down to raw DOM APIs. This question checks whether you understand what frameworks are doing for you — and whether you could debug or write a 3rd-party integration that needs direct DOM access.

Finished reading?

Mark this topic as solved to track your progress.