JavaScript DOM Notes
Document
The DOM Tree & Navigation
Every HTML tag is an object. Nested tags are "children" of the enclosing tag.
-
Nodes vs. Elements:
- Nodes: Include everything (Comments, Text, Elements). Accessed via
childNodes,firstChild,nextSibling. - Elements: HTML tags only (ignores text/comments). Accessed via
children,firstElementChild,nextElementSibling.children– only those children that are element nodes.firstElementChild,lastElementChild– first and last element children.previousElementSibling,nextElementSibling– neighbor elements.parentElement– parent element.
- The
<table>element supports (in addition to the given above) these properties:table.rows– the collection of<tr>elements of the table.table.caption/tHead/tFoot– references to elements<caption>,<thead>,<tfoot>.table.tBodies– the collection of<tbody>elements (can be many according to the standard, but there will always be at least one – even if it is not in the source HTML, the browser will put it in the DOM).<thead>,<tfoot>,<tbody>elements provide therowsproperty:tbody.rows– the collection of<tr>inside.
<tr>:tr.cells– the collection of<td>and<th>cells inside the given<tr>.tr.sectionRowIndex– the position (index) of the given<tr>inside the enclosing<thead>/<tbody>/<tfoot>.tr.rowIndex– the number of the<tr>in the table as a whole (including all table rows).
<td>and<th>:td.cellIndex– the number of the cell inside the enclosing<tr>.
- Nodes: Include everything (Comments, Text, Elements). Accessed via
-
Senior Tip: In interviews, almost always use Element navigation (
children) to avoid dealing with accidental whitespace text nodes.
Searching the DOM
| Method | Searches by... | Can call on an element? | Live? |
|---|---|---|---|
querySelector | CSS-selector | ✔ | - |
querySelectorAll | CSS-selector | ✔ | - |
getElementById | id | - | - |
getElementsByName | name | - | ✔ |
getElementsByTagName | tag or '*' | ✔ | ✔ |
getElementsByClassName | class | ✔ | ✔ |
- querySelector(css) / **querySelectorAll(css)****:
- Uses CSS selectors (e.g.,
.class,#id,div > span). - Returns a Static Collection (NodeList). It does not update if the DOM changes later.
- Uses CSS selectors (e.g.,
- getElementsBy* (TagName, ClassName, Name):
- Returns a Live Collection (HTMLCollection).
- Crucial: If you add a
<div>to the DOM after callinggetElementsByTagName('div'), the collection automatically grows to include it.
- By far the most used are
querySelectorandquerySelectorAll, butgetElement(s)By*can be sporadically helpful or found in the old scripts. Besides that: - There is
elem.matches(css)to check ifelemmatches the given CSS selector. - There is
elem.closest(css)to look for the nearest ancestor that matches the given CSS-selector. Theelemitself is also checked.- Ancestors of an element are: parent, the parent of parent, its parent and so on. The ancestors together form the chain of parents from the element to the top. And let’s mention one more method here to check for the child-parent relationship, as it’s sometimes useful:
elemA.contains(elemB)returns true ifelemBis insideelemA(a descendant ofelemA) or whenelemA==elemB.
Attributes vs. Properties
- Attribute: Written in HTML (string). Accessed via
elem.getAttribute('class'). - Property: The DOM object field. Accessed via
elem.className. - Syncing: Standard properties (id, href) sync. Non-standard ones do not.
- Gotcha:
input.getAttribute('value')gives the initial HTML value.input.valuegives the current user input.
- Gotcha:
- Each DOM node belongs to a certain class. The classes form a hierarchy. The full set of properties and methods come as the result of inheritance. ![[svgviewer-output.svg]]
- Main DOM node properties are:
nodeType: We can use it to see if a node is a text or an element node. It has a numeric value:1for elements,3for text nodes, and a few others for other node types. Read-only.nodeName/tagName: For elements, tag name (uppercased unless XML-mode). For non-element nodesnodeNamedescribes what it is. Read-only.innerHTML: The HTML content of the element. Can be modified.outerHTML: The full HTML of the element. A write operation intoelem.outerHTMLdoes not touchelemitself. Instead it gets replaced with the new HTML in the outer context.nodeValue/data: The content of a non-element node (text, comment). These two are almost the same, usually we usedata. Can be modified.textContent: The text inside the element: HTML minus all<tags>. Writing into it puts the text inside the element, with all special characters and tags treated exactly as text. Can safely insert user-generated text and protect from unwanted HTML insertions.hidden: When set totrue, does the same as CSSdisplay:none.- DOM nodes also have other properties depending on their class. For instance,
<input>elements (HTMLInputElement) supportvalue,type, while<a>elements (HTMLAnchorElement) supporthrefetc. Most standard HTML attributes have a corresponding DOM property.
[!INFO]
console.log(elem)shows the element DOM tree.console.dir(elem)shows the element as a DOM object, good to explore its properties.
Modifying the DOM
- Creation:
document.createElement('div'). - Insertion (Modern):
node.append(...nodes)(at end).node.prepend(...nodes)(at start).node.before()/node.after()(siblings).
- Removal:
node.remove(). - Cloning:
node.cloneNode(deep)(true = deep, false = shallow).
Classes and Styles
- className: The string of all classes (space-separated). Replaces everything.
- classList: The modern way. Methods:
.add(),.remove(),.toggle(),.contains(). - style: Applies inline styles (
elem.style.width = "100px").
Events
Event Propagation
Events travel in 3 phases:
- Capture (top → target): event travels down the DOM tree
- Target: fires on the element itself
- Bubble (target → top): event bubbles back up
// bubbling (default) — handler fires on the way up
elem.addEventListener('click', handler);
// capturing — handler fires on the way down
elem.addEventListener('click', handler, { capture: true });
stopPropagation() — stops the event from travelling further (up or down).
preventDefault() — prevents the browser's default action (e.g. form submit, link follow). Does NOT stop propagation.
Event Delegation
Attach ONE listener to a parent instead of many listeners on children. Uses bubbling.
// Instead of adding listeners to every <li>
document.getElementById('list').addEventListener('click', (e) => {
if (e.target.tagName === 'LI') {
console.log('Clicked:', e.target.textContent);
}
});
Benefits: works for dynamically added children, fewer listeners, better memory.
Common Events
| Category | Events |
|---|---|
| Mouse | click, dblclick, mouseenter, mouseleave, mouseover, mouseout, mousemove |
| Keyboard | keydown, keyup, keypress |
| Form | submit, change, input, focus, blur, reset |
| Window | load, DOMContentLoaded, resize, scroll |
| Drag | dragstart, drag, dragend, drop |
mouseenter vs mouseover:
mouseenterfires once when cursor enters the element, does NOT bubblemouseoverfires when cursor enters element OR any child, DOES bubble
Event Object
elem.addEventListener('click', (e) => {
e.target // element that triggered the event
e.currentTarget // element the listener is attached to
e.type // "click"
e.clientX/Y // mouse position relative to viewport
e.key // key pressed (for keyboard events)
e.preventDefault()
e.stopPropagation()
});