JavaScript: DOM Manipulation
Last updated: 2026-10-13
DOM (Document Object Model) is a tree that the browser creates from the HTML document. By operating on this tree with JavaScript, you can dynamically change the page's content, structure, and attributes—like picking fruit from a tree, grafting new branches, or cutting dead wood.
1. Selecting Elements
The first step in DOM manipulation is always "find it first".
| Method | Returns | Description |
|---|---|---|
getElementById('id') |
Single element | Fastest, id is unique |
getElementsByClassName('cls') |
HTMLCollection | Live collection, syncs with DOM changes |
getElementsByTagName('tag') |
HTMLCollection | Same as above |
querySelector('selector') |
Single element | CSS selector, returns first match |
querySelectorAll('selector') |
NodeList | Static collection, doesn't change with DOM |
💡 Tip:
querySelector family vs getElementBy*: the former uses CSS selectors (more flexible), the latter has slightly better performance. For daily development, prefer querySelector—it's more intuitive.
▶ Example: Comparing Five Selection Methods
▶ Try it Yourself2. Modifying Content
After finding an element, the most common need is to change "what it says".
textContent: reads/writes plain text, safe and efficient.innerHTML: reads/writes HTML strings, can insert tags, but has XSS risk.
⚠️ Note: Never use
innerHTML to insert user-supplied content, otherwise attackers can inject malicious scripts. It's like posting a letter from a stranger directly to the bulletin board—the letter might contain a "bomb".
▶ Example: textContent vs innerHTML
▶ Try it Yourself3. Modifying Attributes
HTML element attributes (id, class, src, href, etc.) can also be read and written with JS.
| Method | Description |
|---|---|
getAttribute('name') |
Read attribute value |
setAttribute('name', 'value') |
Set attribute |
removeAttribute('name') |
Remove attribute |
💡 Tip: Some attributes can be accessed directly with dot notation:
el.id, el.className, el.src. But for custom attributes (data-*), use getAttribute or el.dataset.
▶ Example: Manipulating Link Attributes
▶ Try it Yourself4. Creating and Inserting Elements
One of the core DOM manipulation abilities: "create" an element out of thin air, then attach it to the tree.
| Method | Description |
|---|---|
createElement('tag') |
Create element node |
createTextNode('text') |
Create text node |
appendChild(child) |
Append to end |
insertBefore(new, ref) |
Insert before ref |
▶ Example: Dynamically Adding List Items
▶ Try it Yourself5. Removing and Cloning Elements
| Method | Description |
|---|---|
removeChild(child) |
Parent removes child node |
remove() |
Element removes itself (newer API) |
cloneNode(true/false) |
true = deep clone (including children), false = shallow clone |
💡 Tip:
remove() is simpler than removeChild(), but if you need to get the removed node for further processing, use removeChild()—it returns the removed node.
▶ Example: Removing and Cloning
▶ Try it Yourself❓ FAQ
Q What happens if
querySelector returns null?A Calling any property/method on
null will throw a TypeError. So it's best to check before operating: const el = document.querySelector('.xxx'); if (el) { ... }.A
HTMLCollection is live—it automatically updates when the DOM changes; NodeList from querySelectorAll is a static snapshot. When iterating and adding/removing elements, a static collection is safer, otherwise you might get an infinite loop.Q What happens if you
appendChild a node that already exists?A The node "moves" from its original position to the new position. In the DOM, the same node can only appear once. This is a move, not a copy.
📖 Summary
- Two camps for selecting elements:
getElementBy*(better performance) andquerySelector*(more flexible). For daily use,querySelectoris sufficient. - Use
textContentfor text changes, useinnerHTMLonly when you need HTML. The latter requires XSS prevention. - Attribute operations:
getAttributeto read,setAttributeto write,removeAttributeto delete. - Standard flow for creating elements:
createElement→ set content/attributes →appendChildto mount. - Two ways to remove elements:
remove()(element removes itself),removeChild()(parent removes it, and you get the node back). cloneNode(true)deep-clones including all descendants,cloneNode(false)clones only the shell.
📝 Exercises
- Basic: Create a page that uses
createElementandappendChildto dynamically generate a list containing 5 city names. - Intermediate: Add a delete button to the list from the previous exercise. When clicked, use
removeChildto delete the corresponding list item. - Challenge: Implement a simple "note manager"—an input field + add button. Each time you add a note, create a card with a delete button. Clicking the delete button removes that card.