Searching the DOM
Before you can manipulate an element, you need to find it. JavaScript provides several methods to search the DOM.
Modern Methods: querySelector / querySelectorAll
These are the most versatile โ they accept any CSS selector:
document.querySelector('.card') // first .card element
document.querySelector('#main h2') // first h2 inside #main
document.querySelectorAll('li') // all li elements (NodeList)
document.querySelectorAll('[data-type]') // all elements with data-type
Demo: querySelector in action
HTML
<div id='catalog'>
<div class='card' data-type='fruit'>Apple</div>
<div class='card' data-type='fruit'>Banana</div>
<div class='card' data-type='veg'>Carrot</div>
<div class='card' data-type='veg'>Daikon</div>
</div>
<pre id='sel-output' style='background:#f1f5f9;padding:8px;border-radius:4px;'></pre> JavaScript
const allCards = document.querySelectorAll('.card');
const fruits = document.querySelectorAll('[data-type=fruit]');
const veg = document.querySelectorAll('[data-type=veg]');
const firstCard = document.querySelector('.card');
const out = document.getElementById('sel-output');
out.textContent =
'All cards: ' + allCards.length + '\\n' +
'Fruits: ' + fruits.length + ' (' + fruits[0].textContent + ', ' + fruits[1].textContent + ')' + '\\n' +
'Vegetables: ' + veg.length + '\\n' +
'First card: ' + firstCard.textContent; Live Output Window
Legacy Methods: getElement*
These are faster but less flexible. Use them when you know the exact ID, tag, or class:
document.getElementById('header') // by ID (fastest)
document.getElementsByTagName('p') // by tag name (live HTMLCollection)
document.getElementsByClassName('card') // by class (live HTMLCollection)
document.getElementsByName('email') // by name attribute (NodeList)
Live vs Static Collections
This is important!
| Method | Returns | Live? |
|---|---|---|
getElementById | Single element | N/A |
getElementsByTagName | HTMLCollection | Yes |
getElementsByClassName | HTMLCollection | Yes |
querySelectorAll | NodeList | No |
querySelector | Single element | N/A |
Live means the collection updates automatically when the DOM changes.
Demo: Live vs Static Collections
HTML
<ul id='live-demo'>
<li>Item 1</li>
<li>Item 2</li>
</ul>
<button id='add-btn'>Add Item</button>
<pre id='live-output' style='background:#f1f5f9;padding:8px;border-radius:4px;'></pre> JavaScript
const liveItems = document.getElementsByTagName('li');
const staticItems = document.querySelectorAll('li');
function updateCounts() {
const out = document.getElementById('live-output');
out.textContent =
'Live collection (getElementsByTagName): ' + liveItems.length + '\\n' +
'Static collection (querySelectorAll): ' + staticItems.length;
}
document.getElementById('add-btn').addEventListener('click', function() {
const ul = document.getElementById('live-demo');
const li = document.createElement('li');
li.textContent = 'Item ' + (ul.children.length + 1);
ul.appendChild(li);
// Static items didn't update โ show it
const out = document.getElementById('live-output');
out.textContent =
'Live collection: ' + liveItems.length + ' (auto-updated!)' + '\\n' +
'Static collection: ' + staticItems.length + ' (stale โ still ' + staticItems.length + ')';
});
updateCounts(); Live Output Window
Closest: Finding Ancestors
closest() walks up the DOM tree to find the nearest matching ancestor:
Demo: closest() demo
HTML
<div class='container'>
<article class='post'>
<h3 class='post-title'>Hello World</h3>
</article>
</div>
<pre id='close-output' style='background:#f1f5f9;padding:8px;border-radius:4px;'></pre> JavaScript
const title = document.querySelector('.post-title');
const out = document.getElementById('close-output');
const post = title.closest('.post');
const container = title.closest('.container');
out.textContent =
'title.closest(.post): ' + post.tagName + '.post' + '\\n' +
'title.closest(.container): ' + container.className + '\\n' +
'title.closest(.nonexistent): ' + title.closest('.nonexistent'); Live Output Window
Matches: Checking an Element
matches() checks if an element matches a CSS selector:
element.matches('.card') // true if element has class "card"
element.matches('li:first-child') // true if it's the first li
Method Comparison
| Method | Returns | When to Use |
|---|---|---|
querySelector | Single element | Any CSS selector |
querySelectorAll | NodeList (static) | Multiple elements, complex selectors |
getElementById | Single element | You know the exact ID |
getElementsByTagName | HTMLCollection (live) | All elements of a tag |
getElementsByClassName | HTMLCollection (live) | All elements with a class |
closest | Single element | Find ancestor |
matches | boolean | Check if element matches |
Key Takeaways
querySelectorandquerySelectorAllare the most flexible โ use them by defaultgetElementByIdis the fastest for single elements with IDs- Be aware of live vs static collections to avoid bugs
- Use
closest()to find parent elements matching a selector - Use
matches()to test an element against a selector