Adding, removing, and mutating DOM elements in vanilla JS
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
1// Create a new element2const paragraph = document.createElement('p');3paragraph.textContent = 'Hello, world!';4paragraph.className = 'greeting';56// Add it to the page7document.body.appendChild(paragraph);
Insertion alternatives worth knowing:
1const container = document.querySelector('#container');23// append — adds to the end (can add multiple items and text)4container.append(element1, element2, 'some text');56// prepend — adds to the beginning7container.prepend(element);89// before / after — adds next to the element10existingElement.before(newElement);11existingElement.after(newElement);1213// insertAdjacentHTML — inserts HTML string at a specific position14container.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
1// Modern way — call remove() on the element2const element = document.querySelector('#old-item');3element.remove();45// Older way — remove through the parent6const parent = document.querySelector('#list');7const child = document.querySelector('#old-item');8parent.removeChild(child);
Mutating
Content:
1element.textContent = 'New text'; // safe, plain text2element.innerHTML = '<strong>Bold</strong>'; // parses HTML
Reach for textContent by default — innerHTML with untrusted input is an XSS vector.
Attributes:
1element.setAttribute('data-id', '42');2element.getAttribute('data-id'); // "42"3element.removeAttribute('data-id');45// Or use properties directly6element.id = 'my-element';7element.className = 'active';
Inline styles:
1element.style.color = 'red';2element.style.fontSize = '16px';3element.style.display = 'none';
Classes (prefer this over mashing className strings):
1element.classList.add('active');2element.classList.remove('active');3element.classList.toggle('active');4element.classList.contains('active'); // true/false
Swapping elements
1const oldElement = document.querySelector('#old');2const newElement = document.createElement('div');3newElement.textContent = 'I am new';45oldElement.replaceWith(newElement);
Cloning
1const original = document.querySelector('.card');23// Shallow clone (no children)4const clone = original.cloneNode(false);56// Deep clone (includes all children)7const deepClone = original.cloneNode(true);89document.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.