DOM Manipulation with JavaScript
DOM Manipulation with JavaScript Interview with follow-up questions
1. What is DOM in JavaScript and why is it important?
The Document Object Model (DOM) is a programming interface for HTML documents. When a browser loads an HTML page, it parses the markup and constructs an in-memory tree of objects — the DOM — where every element, attribute, and piece of text becomes a node. JavaScript can then read and modify this tree, and the browser reflects those changes in what is displayed on screen.
Why the DOM matters
Without the DOM, JavaScript would have no structured way to interact with a page's content. The DOM is what makes web pages dynamic:
- Read data from the page (form values, attributes, text content)
- Create, insert, move, or remove elements
- Respond to user events (clicks, keyboard input, scroll)
- Change styles and classes to update appearance without a page reload
- Communicate changes back to the server via fetch and reflect the result instantly
The DOM tree structure
The root is document. Below it is the element, which has and `as children. Every HTML element becomes anElementnode; text inside an element becomes aTextnode; HTML comments becomeCommentnodes. The entire structure is traversable via properties likeparentNode,children,firstElementChild, andnextElementSibling`.
Virtual DOM vs. real DOM
Frameworks like React introduced the Virtual DOM: a lightweight JavaScript representation of the DOM. The framework diffs the virtual tree and applies only the minimal real DOM changes needed. This batching is a performance optimisation — direct DOM manipulation is relatively slow because it can trigger layout recalculations (reflows) and repaints.
Modern APIs
document.querySelector() and document.querySelectorAll() have replaced getElementById and getElementsByClassName for most use cases, offering CSS selector syntax and consistent return types. MutationObserver watches for DOM changes without polling. IntersectionObserver detects when elements enter or leave the viewport.
Follow-up 1
Can you explain the structure of the DOM?
The structure of the DOM is hierarchical, resembling a tree-like structure. At the top of the tree is the document object, which represents the entire web page. The document object has child nodes, which are the HTML elements in the page.
Each HTML element is represented by an object in the DOM tree. These objects are called nodes. Each node can have child nodes, which are the elements nested inside it. Nodes can also have attributes, such as id, class, or src.
Here's an example of the DOM structure for a simple web page:
- document
- html
- head
- title
- body
- div
- h1
- p
Follow-up 2
How does JavaScript interact with the DOM?
JavaScript interacts with the DOM through the document object. The document object provides methods and properties that allow JavaScript to access and manipulate the elements and attributes of the web page.
Here are some common ways JavaScript interacts with the DOM:
Accessing elements: JavaScript can use methods like
getElementById,getElementsByClassName, orquerySelectorto select elements from the DOM.Modifying content: JavaScript can change the content of elements by modifying their
innerHTMLortextContentproperties.Modifying attributes: JavaScript can change the attributes of elements by modifying their
src,href, or other attribute properties.Adding and removing elements: JavaScript can create new elements using the
createElementmethod and add them to the DOM using methods likeappendChildorinsertBefore. It can also remove elements using theremoveChildmethod.Handling events: JavaScript can attach event listeners to elements to respond to user interactions, such as clicks or key presses.
Follow-up 3
What are some common methods used to manipulate the DOM?
There are several common methods used to manipulate the DOM in JavaScript:
getElementById: This method returns the element with the specified
idattribute.getElementsByClassName: This method returns a collection of elements with the specified class name.
querySelector: This method returns the first element that matches a specified CSS selector.
innerHTML: This property allows you to get or set the HTML content of an element.
textContent: This property allows you to get or set the text content of an element.
setAttribute: This method allows you to set the value of an attribute for an element.
appendChild: This method appends a new child element to an existing element.
removeChild: This method removes a child element from its parent.
These are just a few examples, and there are many more methods available for DOM manipulation in JavaScript.
2. How can you add or remove an element in DOM using JavaScript?
Adding elements
The modern approach uses createElement to build the element, configure it, then append or insertAdjacentElement to place it:
const li = document.createElement('li');
li.textContent = 'New item';
li.classList.add('list-item');
const ul = document.querySelector('.my-list');
ul.append(li); // adds at the end
ul.prepend(li); // adds at the start
ul.insertAdjacentElement('beforeend', li); // flexible positioning
append() is preferred over the older appendChild() because it accepts both nodes and strings, and can append multiple items at once.
For inserting relative to a sibling:
const reference = document.querySelector('.existing-item');
reference.after(li); // inserts after the reference element
reference.before(li); // inserts before it
Removing elements
The modern API is simply .remove() on the element itself:
const el = document.querySelector('.to-remove');
el.remove();
The older pattern — el.parentNode.removeChild(el) — still works but is more verbose and is rarely used in new code.
Cloning elements
const clone = original.cloneNode(true); // true = deep clone including children
container.append(clone);
Performance consideration
When inserting many elements at once, use DocumentFragment to batch DOM insertions and avoid repeated reflows:
const fragment = document.createDocumentFragment();
items.forEach(text => {
const li = document.createElement('li');
li.textContent = text;
fragment.append(li);
});
document.querySelector('ul').append(fragment);
Common gotcha: innerHTML = '' clears a container quickly but removes all event listeners attached to child elements. If those listeners are not cleaned up separately, this causes memory leaks. Use replaceChildren() or .remove() on individual children when listener cleanup matters.
Follow-up 1
What are the methods used to add an element?
There are several methods you can use to add an element to the DOM using JavaScript:
appendChild(): This method appends a node as the last child of a parent node.insertBefore(): This method inserts a node before a specified child node within a parent node.innerHTML: This property can be used to set the HTML content of an element, effectively adding new elements.createElement(): This method creates a new element with the specified tag name.
Follow-up 2
What are the methods used to remove an element?
To remove an element from the DOM using JavaScript, you can use the following methods:
removeChild(): This method removes a specified child node from its parent node.parentNode.removeChild(): This method removes the specified node by accessing its parent node and calling theremoveChild()method on it.
Follow-up 3
Can you provide a code example of adding and removing an element?
Sure! Here's an example of adding and removing an element using JavaScript:
// Adding an element
const parentElement = document.getElementById('parent');
const newElement = document.createElement('div');
newElement.textContent = 'New Element';
parentElement.appendChild(newElement);
// Removing an element
const elementToRemove = document.getElementById('elementToRemove');
if (elementToRemove) {
elementToRemove.parentNode.removeChild(elementToRemove);
}
3. What is event bubbling and event capturing in JavaScript?
When a user interacts with an element (a click, keypress, focus, etc.), the browser does not immediately fire the event just on that element. Instead it travels through three phases: capturing, target, and bubbling.
Event Capturing (capture phase)
The event starts at document and travels down through the DOM tree toward the target element. Listeners registered with { capture: true } (or the third argument true) fire during this downward journey:
document.addEventListener('click', handler, { capture: true });
Capturing is rarely used in application code but is useful for intercepting events before they reach their target — for example, in UI frameworks that need to detect clicks outside a modal.
Target phase
The event reaches the element it was originally fired on. Both capture and bubble listeners on the target itself fire at this phase.
Event Bubbling (bubble phase)
After reaching the target, the event bubbles back up through ancestor elements to document. This is the default: listeners registered without { capture: true } fire during bubbling:
document.querySelector('.button').addEventListener('click', handler);
// fires during bubbling
Most DOM events bubble. Notable exceptions: focus, blur, load, scroll, and mouseenter/mouseleave do not bubble (though focusin/focusout do).
Stopping propagation
event.stopPropagation()— prevents the event from travelling further up (or down in capture) the DOM.event.stopImmediatePropagation()— also prevents other listeners on the same element from firing.
Event delegation
Bubbling enables event delegation: attach a single listener to a parent element instead of individual listeners on each child. This is more memory-efficient and works for dynamically added children:
document.querySelector('ul').addEventListener('click', (e) => {
if (e.target.matches('li')) {
console.log('Clicked:', e.target.textContent);
}
});
e.target is the element that was actually clicked; e.currentTarget is the element the listener is attached to.
Follow-up 1
Can you explain the difference between the two?
The main difference between event bubbling and event capturing is the order in which the events are handled.
In event bubbling, the event is first handled by the innermost element and then propagated to its parent elements. This means that the event handlers of the parent elements are triggered after the event handlers of the inner elements.
In event capturing, the event is first handled by the outermost element and then propagated to the innermost element. This means that the event handlers of the inner elements are triggered after the event handlers of the parent elements.
To summarize, event bubbling starts from the innermost element and goes up to the outermost element, while event capturing starts from the outermost element and goes down to the innermost element.
Follow-up 2
How can you stop event propagation?
To stop event propagation, you can use the stopPropagation() method of the Event object. This method prevents further propagation of the current event in both event bubbling and event capturing.
Here's an example of how to use stopPropagation() to stop event propagation:
const button = document.getElementById('myButton');
button.addEventListener('click', function(event) {
event.stopPropagation();
// Event propagation stopped
});
Follow-up 3
In what scenarios would you use event bubbling vs event capturing?
The choice between event bubbling and event capturing depends on the specific requirements of your application.
Event Bubbling: Event bubbling is the default behavior in most browsers. It is commonly used when you want to handle an event on multiple elements in the DOM hierarchy. By attaching a single event listener to a parent element, you can handle the event for all its child elements as well. This can help reduce the number of event listeners and simplify event handling.
Event Capturing: Event capturing is less commonly used but can be useful in certain scenarios. For example, if you have nested elements with overlapping event handlers, event capturing can ensure that the outermost element's event handler is triggered first, regardless of the order in which the elements were added to the DOM.
In general, event bubbling is more widely used and sufficient for most cases. Event capturing is typically used in more complex scenarios where fine-grained control over event handling is required.
4. How can you change the attribute of an HTML element using JavaScript?
There are several ways to read and modify HTML element attributes with JavaScript. The right approach depends on whether you are working with a standard reflected property or an arbitrary attribute.
setAttribute and getAttribute
The general-purpose methods that work for any attribute:
const img = document.querySelector('#avatar');
img.getAttribute('src'); // read
img.setAttribute('src', 'new.jpg'); // write
img.removeAttribute('alt'); // remove
img.hasAttribute('data-active'); // check existence
Direct property access (preferred for standard attributes)
Many HTML attributes are reflected as DOM element properties. Accessing the property is faster, type-safe, and idiomatic:
const input = document.querySelector('input');
input.value = 'hello'; // not setAttribute('value', ...)
input.disabled = true;
input.type = 'email';
const link = document.querySelector('a');
link.href = 'https://example.com'; // returns absolute URL
Note: getAttribute('href') returns the literal attribute value (e.g., /page), while .href returns the resolved absolute URL. This distinction matters when reading links.
data-* attributes and dataset
Custom data- attributes are accessed through the dataset property, which automatically converts kebab-case to camelCase:
// <div>
const el = document.querySelector('div');
el.dataset.userId; // "42"
el.dataset.role; // "admin"
el.dataset.userId = '99'; // sets data-user-id="99"
classList for class attributes
For the class attribute specifically, always use classList rather than setAttribute('class', ...), which overwrites all existing classes:
el.classList.add('active');
el.classList.remove('hidden');
el.classList.toggle('open');
el.classList.contains('selected'); // boolean
el.classList.replace('old', 'new');
Modern selector
Prefer document.querySelector over document.getElementById for new code — it is more flexible and returns null (not undefined) when no match is found.
Follow-up 1
What method would you use to change an attribute?
To change an attribute of an HTML element using JavaScript, you can use the setAttribute() method. This method takes two parameters: the name of the attribute you want to change, and the new value you want to set. For example:
var element = document.getElementById('myElement');
element.setAttribute('src', 'new-image.jpg');
Follow-up 2
Can you provide a code example of changing an attribute?
Sure! Here's an example of how you can change the src attribute of an image element using JavaScript:
<img src="old-image.jpg">
var image = document.getElementById('myImage');
image.setAttribute('src', 'new-image.jpg');
Follow-up 3
What happens if the attribute does not exist on the element?
If the attribute does not exist on the element, the setAttribute() method will create a new attribute with the specified name and value. For example, if you try to change the alt attribute of an image element, but it doesn't exist, the method will create a new alt attribute with the specified value. If you want to check if an attribute exists before changing it, you can use the hasAttribute() method. For example:
var element = document.getElementById('myElement');
if (element.hasAttribute('alt')) {
element.setAttribute('alt', 'new-alt-text');
}
5. What is the difference between innerHTML and textContent in JavaScript?
Both innerHTML and textContent read from or write to the content of a DOM element, but they handle the content differently in ways that matter for both functionality and security.
textContent
Returns the concatenated text content of an element and all its descendants, stripping all HTML tags. When set, it replaces all child content with a single text node — any HTML in the string is treated as literal characters (angle brackets are escaped), not parsed as markup.
const el = document.querySelector('.message');
el.textContent; // "Hello world" (no tags)
el.textContent = '<b>Bold</b>'; // renders as literal text: <b>Bold</b>
Use textContent when displaying user-provided strings. Because it never parses HTML, it is immune to cross-site scripting (XSS) attacks.
innerHTML
Returns the HTML markup inside an element as a string, including all tags. When set, it parses the string as HTML and replaces the element's children with the resulting DOM nodes.
el.innerHTML; // "<strong>Hello</strong> world"
el.innerHTML = '<strong>Hi</strong>'; // parses and renders bold text
Use innerHTML when you control the HTML string and need to insert real markup.
Security risk with innerHTML
Setting innerHTML with unsanitised user input is a primary XSS vector:
// DANGEROUS — do not do this
el.innerHTML = userInput; // if userInput is '<img src="x">'
The safe alternatives:
- Use
textContentfor text. - Use
createElement+appendto build nodes programmatically. - Use
el.setHTML()(the new Sanitizer API, shipping in modern browsers) for cases where you need to allow a subset of HTML from untrusted input.
innerText vs textContent
A related gotcha: innerText is layout-aware — it returns what is visibly rendered (respecting CSS display: none and visibility: hidden) and normalises whitespace. textContent returns all text in the DOM regardless of visibility and preserves whitespace. textContent is faster and more predictable for programmatic use.
Follow-up 1
In what scenarios would you use innerHTML vs textContent?
You would use innerHTML when you need to manipulate or retrieve the HTML content of an element, including its child elements. This is useful when you want to update the structure or add new elements to the content.
On the other hand, you would use textContent when you only need to manipulate or retrieve the plain text content of an element, without any HTML tags. This is useful when you want to update or retrieve the text content without affecting the structure or child elements of the element.
Follow-up 2
What are the security implications of using innerHTML?
Using innerHTML to set content can introduce security vulnerabilities if the content is not properly sanitized. When using innerHTML, any HTML tags or scripts included in the content will be executed, which can lead to cross-site scripting (XSS) attacks.
To mitigate this risk, it is important to sanitize any user-generated or untrusted content before using innerHTML to set it. This can be done by using a library or framework that provides HTML sanitization functionality, or by manually sanitizing the content by removing or escaping any potentially dangerous HTML tags or scripts.
Follow-up 3
Can you provide a code example of using both methods?
Certainly! Here's an example that demonstrates the usage of both innerHTML and textContent:
// HTML
<div></div>
// JavaScript
var myElement = document.getElementById('myElement');
// Using innerHTML
myElement.innerHTML = '<strong>Hello, <em>world!</em></strong>';
console.log(myElement.innerHTML); // Output: <strong>Hello, <em>world!</em></strong>
// Using textContent
myElement.textContent = 'Hello, world!';
console.log(myElement.textContent); // Output: Hello, world!
Live mock interview
Mock interview: DOM Manipulation with JavaScript
- Read your scene and goals
- Talk it out; goals tick off live
- Get a score and stronger lines
Your voice and your AI key never touch our servers; the key stays in this browser and is sent only to Google. Only your round scores are saved to track progress.