Learning Objectives
- Move between nodes with parent, child, and sibling properties
- Explain why
firstChildandfirstElementChilddiffer, and when it bites - Walk upward to a matching ancestor with
closest() - Traverse a subtree depth-first with
firstChild/nextSibling
Two flavors of every relationship
Indent your markup like a civilized person and every element grows whitespace-only text children. So the tree API splits each relationship in two: the node properties see everything — elements, text, comments — and the element properties skip to tags only.
When you are working with page structure — which is most of the time — use the element flavor and the whitespace never troubles you. Reach for the node flavor only when text nodes are the point, and then check nodeType: 1 is an element, 3 is text, 8 is a comment.
el.firstChild on nicely indented markup returns a text node holding a newline and some spaces, and the next property access on what you assumed was an element comes back undefined. If you meant the first tag, say firstElementChild.Walking up, and walking everything
parentNode climbs one level. closest() climbs with a selector — from the current element upward, returning the first ancestor (or self) that matches:
That one call is the backbone of event delegation in the Events series: from whatever small thing was clicked, walk up to the component that owns it. And with just firstChild and nextSibling you can visit an entire subtree — the depth-first walk every serializer, sanitizer, and framework diff is built on:
Live demo
A small nested tree — a list inside a div inside a div — with each traversal one button press. Whatever a walk reaches gets marked in the sample, so you can check your prediction against the tree. Pay attention to section 2: firstChild versus firstElementChild on the same element, and the childNodes dump where the whitespace text nodes finally show themselves. Then run the depth-first walk and read the indented output against the markup.
Walk or query?
Both reach nodes; they answer different questions. A query answers “find me the nodes matching this description, wherever they are.” A walk answers “from the node I am holding, give me its neighbor.” Inside a delegated event handler, holding the element that was clicked, closest() and children are the natural moves — re-querying the whole document to find where you already are is the roundabout version.
Next Steps
You can reach any node in the tree. In Step 4: Attributes and mappings, we start changing what we find:
- Read and write attributes with
getAttribute/setAttribute - Meet the property mapping — and the renamed reserved words like
classNameandhtmlFor - Flip visual state with
classList - Attach your own data with
data-*and read it back throughdataset