π What is DOM Traversing?
DOM Traversing means moving through HTML elements relative to a selected element β such as moving to its parent, children, or siblings.
π Instead of selecting directly, you navigate the DOM tree.
π³ Sample HTML (Used in All Examples)
<div id="container">
<h2>Title</h2>
<p>Paragraph 1</p>
<p>Paragraph 2</p>
</div>πΌ 1. parentElement
βοΈ Purpose: Moves upward to get the parent element.
element.parentElementπ§ͺ Example
const para = document.querySelector("p");
console.log(para.parentElement);<div id="container">...</divπ Explanation
Returns the direct parent element
Skips text and comment nodes
π½ 2. children
βοΈ Purpose: Selects only element children of a parent.
element.childrenπ§ͺ Example
const box = document.getElementById("container");
console.log(box.children);HTMLCollection(3) [h2, p, p]π Explanation
Returns HTMLCollection
Does not include text nodes (spaces, line breaks)
π½ 3. firstElementChild
βοΈ Purpose: Selects the first child element.
element.firstElementChildπ§ͺ Example
const box = document.getElementById("container");
console.log(box.firstElementChild.textContent);Titleπ Explanation
Skips text nodes
Useful when structure is known
β‘οΈ 4. nextElementSibling
βοΈ Purpose: Moves to the next sibling element.
element.nextElementSiblingπ§ͺ Example
const firstPara = document.querySelector("p");
console.log(firstPara.nextElementSibling.textContent);Paragraph 2π Explanation
Ignores text nodes
Returns
nullif no sibling exists
π½ 5. lastElementChild
βοΈ Purpose: Selects the last child element.
element.lastElementChildπ§ͺ Example
console.log(box.lastElementChild.textContent);Paragraph 2β¬
οΈ 6. previousElementSibling
βοΈ Purpose: Moves to the previous sibling element.
element.previousElementSiblingπ§ͺ Example
const secondPara = document.querySelectorAll("p")[1];
console.log(secondPara.previousElementSibling.textContent);Paragraph 1<div class="infographic-domtraverse">
<style>
.infographic-domtraverse {
--ink: #1a1a1a;
--ink-soft: #5c5c5c;
--paper: #ffffff;
--paper-alt: #f0ece4;
--accent: #2563eb;
--accent-soft:#e3ebfd;
--line: #ddd6c9;
--good: #1a8a5f;
--good-soft: #e1f2ea;
box-sizing: border-box;
max-width: 880px;
margin: 0 auto;
font-family: 'Inter', system-ui, sans-serif;
color: var(--ink);
background: var(--paper);
overflow-x: hidden;
}
.infographic-domtraverse[data-theme="dark"] {
--ink: #e8e6e1;
--ink-soft: #9a968c;
--paper: #121212;
--paper-alt: #1e1e26;
--accent: #5b8def;
--accent-soft:#202942;
--line: #2c313d;
--good: #4fbf8f;
--good-soft: #16281f;
}
.infographic-domtraverse * { box-sizing: border-box; }
.infographic-domtraverse h1 { font-family: 'Fraunces', Georgia, serif; font-weight: 600; margin: 0; }
.infographic-domtraverse p { margin: 0; }
.infographic-domtraverse button { font-family: inherit; }
.tv-wrap { padding: clamp(1.25rem, 5vw, 2.5rem) clamp(1.1rem, 5vw, 3rem) 2rem; }
.tv-hero { text-align: center; margin-bottom: 1.2rem; }
.tv-hero h1 { font-size: clamp(1.35rem, 4.5vw, 1.85rem); }
.tv-hero p { color: var(--ink-soft); margin-top: 0.4rem; font-size: 0.84rem; }
.tv-tabs { display: flex; flex-wrap: wrap; gap: 0.35rem; justify-content: center; margin-bottom: 1.2rem; }
.tv-tab { border: 1px solid var(--line); background: var(--paper-alt); color: var(--ink-soft); padding: 0.34rem 0.55rem; font-size: 0.6rem; font-weight: 700; cursor: pointer; font-family: 'IBM Plex Mono', monospace; }
.tv-tab.is-active { border-color: var(--accent); background: var(--accent-soft); color: var(--accent); }
.tv-tab:hover:not(.is-active) { border-color: var(--ink-soft); color: var(--ink); }
/* shared mini page, reused across all tabs */
.tv-page { border: 1.5px solid var(--line); background: var(--paper-alt); border-radius: 6px; overflow: hidden; margin-bottom: 1rem; }
.tv-page-bar { background: #2b2b2b; padding: 0.4rem 0.6rem; display: flex; gap: 0.3rem; }
.tv-page-dot { width: 8px; height: 8px; border-radius: 50%; background: #555; }
.tv-page-body { padding: 0.9rem 1rem; background: var(--paper); }
.tv-container { border: 1.5px dashed var(--line); border-radius: 5px; padding: 0.5rem; transition: border-color 0.35s ease, background 0.35s ease, box-shadow 0.35s ease; }
.tv-el { border: 1.5px dashed var(--line); border-radius: 4px; padding: 0.32rem 0.55rem; margin-top: 0.4rem; font-size: 0.78rem; color: var(--ink); transition: border-color 0.35s ease, background 0.35s ease, box-shadow 0.35s ease, opacity 0.3s ease; }
.tv-el:first-child { margin-top: 0; }
.tv-tag { font-family: 'IBM Plex Mono', monospace; font-size: 0.56rem; color: var(--ink-soft); display: block; margin-bottom: 0.1rem; }
.is-start { border-style: solid; border-color: var(--accent); background: var(--accent-soft); box-shadow: 0 0 0 3px var(--accent-soft); }
.is-target { border-style: solid; border-color: var(--good); background: var(--good-soft); box-shadow: 0 0 0 3px var(--good-soft); }
.tv-panel { display: none; }
.tv-panel.is-active { display: block; }
.tv-code { background: #1e1e1e; color: #d4d4d4; border-radius: 5px; padding: 0.6rem 0.8rem; font-family: 'IBM Plex Mono', monospace; font-size: 0.68rem; line-height: 1.6; margin-bottom: 1rem; white-space: pre; overflow-x: auto; }
.tok-kw { color: #569cd6; }
.tok-fn { color: #dcdcaa; }
.tok-str { color: #ce9178; }
.tok-var { color: #9cdcfe; }
.tok-punc { color: #d4d4d4; }
.tok-num { color: #b5cea8; }
.tv-play { display: block; margin: 0 auto; border: none; background: var(--accent); color: #fff; padding: 0.5rem 1.2rem; font-size: 0.8rem; font-weight: 600; cursor: pointer; }
.tv-play:active { transform: scale(0.96); }
.tv-console { margin: 1rem auto 0; max-width: 340px; text-align: left; border: 1.5px solid var(--line); background: var(--paper-alt); padding: 0.5rem 0.75rem; font-family: 'IBM Plex Mono', monospace; font-size: 0.68rem; min-height: 1.8em; }
.tv-console .tv-cline { opacity: 0; transition: opacity 0.25s ease; color: var(--good); display: block; }
.tv-console .tv-cline.is-shown { opacity: 1; }
.tv-note { text-align: center; font-size: 0.78rem; color: var(--ink-soft); padding-top: 1.3rem; }
.tv-note strong { color: var(--ink); }
.tv-legend { display: flex; justify-content: center; gap: 1.2rem; margin-top: 0.7rem; margin-bottom: 1.4rem; font-size: 0.68rem; color: var(--ink-soft); flex-wrap: wrap; }
.tv-legend span { display: inline-flex; align-items: center; gap: 0.3rem; }
.tv-legend .dot { width: 9px; height: 9px; border-radius: 50%; display: inline-block; }
.tv-legend .dot.st { background: var(--accent); }
.tv-legend .dot.tg { background: var(--good); }
@media (prefers-reduced-motion: reduce) {
.infographic-domtraverse *, .infographic-domtraverse *::before, .infographic-domtraverse *::after {
animation-duration: 0.001ms !important; transition-duration: 0.001ms !important;
}
}
</style>
<div class="tv-wrap">
<div class="tv-hero">
<h1>Moving around the DOM</h1>
<p>Same tiny tree β start (blue) always jumps to the target (green).</p>
</div>
<div class="tv-tabs">
<button class="tv-tab is-active" data-tab="parent" type="button">parentElement</button>
<button class="tv-tab" data-tab="children" type="button">children</button>
<button class="tv-tab" data-tab="first" type="button">firstElementChild</button>
<button class="tv-tab" data-tab="last" type="button">lastElementChild</button>
<button class="tv-tab" data-tab="next" type="button">nextElementSibling</button>
<button class="tv-tab" data-tab="prev" type="button">previousElementSibling</button>
</div>
<div class="tv-page">
<div class="tv-page-bar"><div class="tv-page-dot"></div><div class="tv-page-dot"></div><div class="tv-page-dot"></div></div>
<div class="tv-page-body">
<div class="tv-container" id="elContainer">
<span class="tv-tag"><div id="container"></span>
<div class="tv-el" id="elH2"><span class="tv-tag"><h2></span>Title</div>
<div class="tv-el" id="elP1"><span class="tv-tag"><p></span>Paragraph 1</div>
<div class="tv-el" id="elP2"><span class="tv-tag"><p></span>Paragraph 2</div>
</div>
</div>
</div>
<div class="tv-legend">
<span><span class="dot st"></span> start element</span>
<span><span class="dot tg"></span> where it moves to</span>
</div>
<!-- parentElement -->
<div class="tv-panel is-active" data-panel="parent">
<div class="tv-code"><span class="tok-kw">const</span> <span class="tok-var">para</span> <span class="tok-punc">=</span> <span class="tok-var">document</span><span class="tok-punc">.</span><span class="tok-fn">querySelector</span><span class="tok-punc">(</span><span class="tok-str">"p"</span><span class="tok-punc">);</span>
<span class="tok-var">console</span><span class="tok-punc">.</span><span class="tok-fn">log</span><span class="tok-punc">(</span><span class="tok-var">para</span><span class="tok-punc">.</span><span class="tok-var">parentElement</span><span class="tok-punc">);</span></div>
<button class="tv-play" data-run="parent" type="button">run</button>
<div class="tv-console"><span class="tv-cline" id="outParent"><div id="container">...</div></span></div>
<p class="tv-note">Steps <strong>up</strong> one level. Skips text and comment nodes.</p>
</div>
<!-- children -->
<div class="tv-panel" data-panel="children">
<div class="tv-code"><span class="tok-kw">const</span> <span class="tok-var">box</span> <span class="tok-punc">=</span> <span class="tok-var">document</span><span class="tok-punc">.</span><span class="tok-fn">getElementById</span><span class="tok-punc">(</span><span class="tok-str">"container"</span><span class="tok-punc">);</span>
<span class="tok-var">console</span><span class="tok-punc">.</span><span class="tok-fn">log</span><span class="tok-punc">(</span><span class="tok-var">box</span><span class="tok-punc">.</span><span class="tok-var">children</span><span class="tok-punc">);</span></div>
<button class="tv-play" data-run="children" type="button">run</button>
<div class="tv-console"><span class="tv-cline" id="outChildren">HTMLCollection(3) [h2, p, p]</span></div>
<p class="tv-note">All element children at once β <strong>no text nodes</strong> (spaces, line breaks) included.</p>
</div>
<!-- firstElementChild -->
<div class="tv-panel" data-panel="first">
<div class="tv-code"><span class="tok-kw">const</span> <span class="tok-var">box</span> <span class="tok-punc">=</span> <span class="tok-var">document</span><span class="tok-punc">.</span><span class="tok-fn">getElementById</span><span class="tok-punc">(</span><span class="tok-str">"container"</span><span class="tok-punc">);</span>
<span class="tok-var">console</span><span class="tok-punc">.</span><span class="tok-fn">log</span><span class="tok-punc">(</span><span class="tok-var">box</span><span class="tok-punc">.</span><span class="tok-var">firstElementChild</span><span class="tok-punc">.</span><span class="tok-var">textContent</span><span class="tok-punc">);</span></div>
<button class="tv-play" data-run="first" type="button">run</button>
<div class="tv-console"><span class="tv-cline" id="outFirst">"Title"</span></div>
<p class="tv-note">The first element child, whatever it is β skips text nodes.</p>
</div>
<!-- lastElementChild -->
<div class="tv-panel" data-panel="last">
<div class="tv-code"><span class="tok-var">console</span><span class="tok-punc">.</span><span class="tok-fn">log</span><span class="tok-punc">(</span><span class="tok-var">box</span><span class="tok-punc">.</span><span class="tok-var">lastElementChild</span><span class="tok-punc">.</span><span class="tok-var">textContent</span><span class="tok-punc">);</span></div>
<button class="tv-play" data-run="last" type="button">run</button>
<div class="tv-console"><span class="tv-cline" id="outLast">"Paragraph 2"</span></div>
<p class="tv-note">The last element child β same idea, other end.</p>
</div>
<!-- nextElementSibling -->
<div class="tv-panel" data-panel="next">
<div class="tv-code"><span class="tok-kw">const</span> <span class="tok-var">firstPara</span> <span class="tok-punc">=</span> <span class="tok-var">document</span><span class="tok-punc">.</span><span class="tok-fn">querySelector</span><span class="tok-punc">(</span><span class="tok-str">"p"</span><span class="tok-punc">);</span>
<span class="tok-var">console</span><span class="tok-punc">.</span><span class="tok-fn">log</span><span class="tok-punc">(</span><span class="tok-var">firstPara</span><span class="tok-punc">.</span><span class="tok-var">nextElementSibling</span><span class="tok-punc">.</span><span class="tok-var">textContent</span><span class="tok-punc">);</span></div>
<button class="tv-play" data-run="next" type="button">run</button>
<div class="tv-console"><span class="tv-cline" id="outNext">"Paragraph 2"</span></div>
<p class="tv-note">One step <strong>sideways, forward</strong>. Returns <strong>null</strong> if there's nothing after it.</p>
</div>
<!-- previousElementSibling -->
<div class="tv-panel" data-panel="prev">
<div class="tv-code"><span class="tok-kw">const</span> <span class="tok-var">secondPara</span> <span class="tok-punc">=</span> <span class="tok-var">document</span><span class="tok-punc">.</span><span class="tok-fn">querySelectorAll</span><span class="tok-punc">(</span><span class="tok-str">"p"</span><span class="tok-punc">)[</span><span class="tok-num">1</span><span class="tok-punc">];</span>
<span class="tok-var">console</span><span class="tok-punc">.</span><span class="tok-fn">log</span><span class="tok-punc">(</span><span class="tok-var">secondPara</span><span class="tok-punc">.</span><span class="tok-var">previousElementSibling</span><span class="tok-punc">.</span><span class="tok-var">textContent</span><span class="tok-punc">);</span></div>
<button class="tv-play" data-run="prev" type="button">run</button>
<div class="tv-console"><span class="tv-cline" id="outPrev">"Paragraph 1"</span></div>
<p class="tv-note">One step <strong>sideways, backward</strong>. Also <strong>null</strong> if nothing's before it.</p>
</div>
</div>
</div>
<script>
(function () {
const wrapper = document.currentScript.closest('.infographic-domtraverse')
|| document.querySelector('.infographic-domtraverse');
const bodyAttr = document.body.getAttribute('data-darkmode');
let dark;
if (bodyAttr === 'true') { dark = true; }
else if (bodyAttr === 'false') { dark = false; }
else {
const match = document.cookie.match(/(?:^|;\s*)darkMode=([^;]+)/);
dark = match ? match[1] === 'true' : false;
}
if (dark) wrapper.setAttribute('data-theme', 'dark');
const els = {
container: wrapper.querySelector('#elContainer'),
h2: wrapper.querySelector('#elH2'),
p1: wrapper.querySelector('#elP1'),
p2: wrapper.querySelector('#elP2'),
};
const allEls = Object.values(els);
function clearHighlights() {
allEls.forEach(el => el.classList.remove('is-start', 'is-target'));
}
const configs = {
parent: { start: ['p1'], target: ['container'], out: 'outParent' },
children: { start: ['container'], target: ['h2', 'p1', 'p2'], out: 'outChildren' },
first: { start: ['container'], target: ['h2'], out: 'outFirst' },
last: { start: ['container'], target: ['p2'], out: 'outLast' },
next: { start: ['p1'], target: ['p2'], out: 'outNext' },
prev: { start: ['p2'], target: ['p1'], out: 'outPrev' },
};
function runTab(key) {
clearHighlights();
const cfg = configs[key];
const out = wrapper.querySelector('#' + cfg.out);
out.classList.remove('is-shown');
void out.offsetWidth;
setTimeout(() => {
cfg.start.forEach(id => els[id].classList.add('is-start'));
}, 60);
setTimeout(() => {
cfg.target.forEach(id => els[id].classList.add('is-target'));
}, 350);
setTimeout(() => out.classList.add('is-shown'), 550);
}
/* tabs */
wrapper.querySelectorAll('.tv-tab').forEach(tab => {
tab.addEventListener('click', () => {
wrapper.querySelectorAll('.tv-tab').forEach(t => t.classList.remove('is-active'));
wrapper.querySelectorAll('.tv-panel').forEach(p => p.classList.remove('is-active'));
tab.classList.add('is-active');
wrapper.querySelector('.tv-panel[data-panel="' + tab.dataset.tab + '"]').classList.add('is-active');
clearHighlights();
});
});
/* run buttons */
wrapper.querySelectorAll('.tv-play').forEach(btn => {
btn.addEventListener('click', () => runTab(btn.dataset.run));
});
})();
</script>π― Real-World Use Case
// Highlight all children
Array.from(box.children).forEach(child => {
child.style.border = "1px solid blue";
});
// Move from one element to another
document.querySelector("h2")
.nextElementSibling
.style.color = "red";