Conceptual Question

Adding, removing, and mutating DOM elements in vanilla JS

React Ecosystem

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
1// Create a new element
2const paragraph = document.createElement('p');
3paragraph.textContent = 'Hello, world!';
4paragraph.className = 'greeting';
5
6// Add it to the page
7document.body.appendChild(paragraph);

Insertion alternatives worth knowing:

JAVASCRIPT
1const container = document.querySelector('#container');
2
3// append — adds to the end (can add multiple items and text)
4container.append(element1, element2, 'some text');
5
6// prepend — adds to the beginning
7container.prepend(element);
8
9// before / after — adds next to the element
10existingElement.before(newElement);
11existingElement.after(newElement);
12
13// insertAdjacentHTML — inserts HTML string at a specific position
14container.insertAdjacentHTML(
15 'beforeend',
16 '<p>New paragraph</p>'
17);

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

Removing

JAVASCRIPT
1// Modern way — call remove() on the element
2const element = document.querySelector('#old-item');
3element.remove();
4
5// Older way — remove through the parent
6const parent = document.querySelector('#list');
7const child = document.querySelector('#old-item');
8parent.removeChild(child);

Mutating

Content:

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

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

Attributes:

JAVASCRIPT
1element.setAttribute('data-id', '42');
2element.getAttribute('data-id'); // "42"
3element.removeAttribute('data-id');
4
5// Or use properties directly
6element.id = 'my-element';
7element.className = 'active';

Inline styles:

JAVASCRIPT
1element.style.color = 'red';
2element.style.fontSize = '16px';
3element.style.display = 'none';

Classes (prefer this over mashing className strings):

JAVASCRIPT
1element.classList.add('active');
2element.classList.remove('active');
3element.classList.toggle('active');
4element.classList.contains('active'); // true/false

Swapping elements

JAVASCRIPT
1const oldElement = document.querySelector('#old');
2const newElement = document.createElement('div');
3newElement.textContent = 'I am new';
4
5oldElement.replaceWith(newElement);

Cloning

JAVASCRIPT
1const original = document.querySelector('.card');
2
3// Shallow clone (no children)
4const clone = original.cloneNode(false);
5
6// Deep clone (includes all children)
7const deepClone = original.cloneNode(true);
8
9document.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.

Continue with nearby questions from the same topic cluster.