COMPUTER PROGRAMMING 1 (JAVASCRIPT) • WEB BASICS (DOM & EVENTS)

Selecting DOM Elements — I can select elements with querySelector/querySelectorAll in supported tasks.

Learn to pinpoint any HTML element on a page so your JavaScript code can read, change, or animate it.

Historical Context & Motivation

In the early days of the web, HTML pages were completely static — once the browser loaded a page, nothing could change. Developers dreamed of pages that could respond to a user's click, update text in real time, or highlight an important paragraph. To make that happen, JavaScript needed a way to reach into the page and grab specific elements. The story of how we got the tools we use today is a journey through competing browsers, messy workarounds, and eventual standardization.

1995
JavaScript Is Born
Brendan Eich creates JavaScript at Netscape in just ten days. Early scripts could only access a few hard-coded collections like document.forms and document.images — selecting an arbitrary element was impossible.
1998
DOM Level 1 Standard
The W3C publishes the first official DOM specification. It introduces getElementById(), letting developers select one element by its unique ID — a huge step forward.
2006
jQuery Simplifies Selection
The jQuery library introduces a single $() function that accepts any CSS selector. It becomes wildly popular because native DOM methods are still limited and verbose.
2013
querySelector Gains Full Support
All major browsers fully support querySelector() and querySelectorAll(), which were standardized in the Selectors API. Developers can now use CSS selectors natively — no library required.

The central question these tools answer is simple: How do I tell JavaScript exactly which HTML element I want to work with? Today, querySelector and querySelectorAll are the modern, go-to methods for answering that question. They accept the same CSS selector syntax you already know from stylesheets, making them intuitive and powerful.

Core Principles & Definitions

Before diving into code, you need to understand a few foundational ideas. The Document Object Model (DOM) is a tree-like representation of your HTML page that the browser builds in memory. Each HTML tag — every <div>, <p>, or <button> — becomes a node in that tree. JavaScript uses the DOM as a bridge to read or modify the page.

1

CSS Selectors as Addresses

A CSS selector is a pattern string like "#main", ".card", or "h2". It tells the browser which element(s) you mean, just like a street address identifies a building.
2

querySelector — First Match

document.querySelector(selector) scans the DOM from top to bottom and returns the first element that matches. If nothing matches, it returns null.
3

querySelectorAll — All Matches

document.querySelectorAll(selector) returns a NodeList containing every element that matches. A NodeList looks like an array but is not quite one — though you can loop through it with forEach.
4

Selector Types You Already Know

ID selectors use #, class selectors use ., and tag selectors use the element name directly. You can combine them just like in a CSS stylesheet: "div.card > h2".
✦ KEY TAKEAWAY
Think of the DOM as a giant filing cabinet and querySelector as your hand reaching in to pull out one specific folder. If you need every folder with the same label, use querySelectorAll — it pulls out all matching folders at once and stacks them in a neat pile (a NodeList) for you to go through one by one.

Visual Explanation — The DOM Tree

The diagram below shows a small HTML page rendered as a DOM tree. When you call document.querySelector(".highlight"), the browser walks the tree from the top (document) downward, checking each node until it finds the first element with class="highlight". That element is returned to your JavaScript code.

The browser starts at document (top) and walks downward through <html>, <body>, and into <ul> until it hits the first <li class="highlight"> — that element (highlighted in cyan) is returned.

Notice that the second <li> node in the tree does not have the highlight class, so it is skipped. If you used querySelectorAll("li") instead, both list items would be collected into a NodeList. The key difference is singular (first match) versus plural (all matches).

How It Works — Syntax & Return Values

Both methods live on the document object (though you can also call them on any element to search only within that element's children). Understanding their exact syntax and return values is essential for writing bug-free code.

querySelector Syntax

QUERYSELECTOR
const element = document.querySelector("cssSelector");
cssSelector — any valid CSS selector string (e.g., "#nav", ".btn", "div > p"). Returns the first matching Element or null if no match is found.

querySelectorAll Syntax

QUERYSELECTORALL
const nodeList = document.querySelectorAll("cssSelector");
Returns a static NodeList of all matching elements. "Static" means the list is a snapshot — if the DOM changes later, the NodeList does not update automatically.

Common Selector Patterns

Frequently used CSS selector patterns with querySelector and querySelectorAll
SelectorWhat It MatchesExample
"#hero"Element with id="hero"querySelector("#hero")
".card"All elements with class="card"querySelectorAll(".card")
"p"All <p> elementsquerySelectorAll("p")
"ul > li.active"Direct <li> children of <ul> with class="active"querySelectorAll("ul > li.active")
"input[type='email']"Input elements with type attribute set to emailquerySelector("input[type='email']")
⚠️ Null Check Tip
Because querySelector returns null when no match is found, always guard your code: if (el !== null) { /* safe to use el */ }. Trying to read a property on null causes a "Cannot read properties of null" error — one of the most common bugs for beginners.

Detailed Breakdown — Selector Types & Scoping

Understanding the different categories of CSS selectors will help you choose the right one for each task. Selectors range from simple (a single tag name) to complex (multiple combinators and pseudo-classes). The diagram below groups the most useful selectors by category, along with their relative specificity from least to most targeted.

Selector categories organized from broadest (tag selectors) to most targeted (ID selectors). Combinators and pseudo-classes add precision within any category. The spectrum arrow at the bottom illustrates increasing specificity from left to right.

Scoped Selections

You are not limited to searching the entire document. Any element can be the starting point for a search. For example, if you have a reference to a <section> element stored in a variable called section, you can write section.querySelector(".title") to find the first .title element only inside that section. This is called a scoped selection, and it keeps your code precise — especially on pages with many repeated components.

Worked Example — Building an Interactive To-Do List

Imagine you have a simple to-do list in HTML and you want JavaScript to mark a task as complete when the user clicks a button. Walk through each step to see how querySelector and querySelectorAll fit into the workflow.

📄 Starting HTML
Assume this HTML is on the page: <ul id="tasks"> <li class="task">Study JavaScript</li> <li class="task">Read chapter 4</li> <li class="task done">Install VS Code</li> </ul> <button id="clear-btn">Clear completed</button>
Selecting & Modifying DOM Elements
1
Step 1 — Select the task list containerWe need a reference to the <ul> so we can work with its children later. Because the list has a unique id, an ID selector is perfect.
const taskList = document.querySelector("#tasks"); — returns the single <ul> element.
2
Step 2 — Select all task itemsThere are three <li> elements sharing the class task. We want all of them, so we use querySelectorAll.
const allTasks = document.querySelectorAll(".task"); — returns a NodeList with 3 items.
3
Step 3 — Loop through and log each taskA NodeList supports forEach, so we can iterate just like with an array. Inside the loop, task.textContent gives us the visible text of each list item.
allTasks.forEach(task => console.log(task.textContent)); — prints "Study JavaScript", "Read chapter 4", "Install VS Code".
4
Step 4 — Select the clear button and add a click handlerWe grab the button by its ID, then attach an event listener. Inside the listener, we select only the completed tasks using a compound selector ".task.done" (elements that have both classes).
const clearBtn = document.querySelector("#clear-btn"); clearBtn.addEventListener("click", () => { const done = document.querySelectorAll(".task.done"); done.forEach(item => item.remove()); }); — clicking the button removes the "Install VS Code" item from the page.
5
Step 5 — Verify with a scoped selectionAfter removal, we can confirm how many tasks remain by using a scoped search on the list container we saved in Step 1.
console.log(taskList.querySelectorAll(".task").length); — outputs 2, confirming the completed task was removed.

querySelector vs. Older DOM Methods

You may still see older selection methods in tutorials and codebases. It helps to know how querySelector and querySelectorAll compare so you can pick the right tool and read legacy code without confusion.

Comparison of DOM selection methods
MethodReturnsAccepts CSS Selectors?Best For
getElementById()Single elementNo — ID string only (no #)Fastest lookup for a known ID
getElementsByClassName()Live HTMLCollectionNo — class name only (no .)Rare; live collection can cause surprises
getElementsByTagName()Live HTMLCollectionNo — tag name onlyRare in modern code
querySelector()Single element or nullYes — any CSS selectorModern default for one element
querySelectorAll()Static NodeListYes — any CSS selectorModern default for multiple elements
🔄 LIVE vs. STATIC
A live collection is like a search engine that re-runs itself every time you look at the results — add or remove elements and the list changes instantly. A static NodeList (from querySelectorAll) is like printing that search result onto paper — it won't change even if the page does. Static lists are usually easier to reason about and avoid unexpected bugs.

Connection to Advanced DOM Techniques

Once you are comfortable with querySelector and querySelectorAll, you will be ready to explore more advanced DOM patterns. The table below previews how these foundational skills connect to topics you will encounter in later courses and projects.

From basics to advanced DOM concepts
What You Know NowWhere It Leads
Selecting elements and reading their textDOM traversal — walking the tree with parentNode, children, nextElementSibling
Adding event listeners to selected elementsEvent delegation — attaching one listener to a parent instead of many to children
Looping through a NodeList with forEachHigher-order iteration — spreading into an array to use map, filter, and reduce
Changing element content with textContent or innerHTMLTemplate literals and frameworks (React, Vue) that manage DOM updates automatically
Selecting by CSS selectorsDynamic class toggling, CSS animations triggered by JavaScript

Frameworks like React and Vue abstract away much of the manual DOM selection you learn here, but understanding the underlying mechanism gives you a critical advantage. When a framework does something unexpected, knowing how querySelector works lets you debug at the browser level — a skill that separates effective developers from those who feel lost when things break.

Practice Problems

Test your understanding with these five problems. They start with a straightforward concept check and build toward scenarios that require you to combine multiple ideas from the lesson.

PROBLEM 1 — CONCEPTUAL
What is the key difference between querySelector and querySelectorAll? In what situation would choosing the wrong one cause a bug?
PROBLEM 2 — BASIC
Write a single line of JavaScript that selects the first <img> element inside a <div> with the class gallery and stores it in a variable called firstPhoto.
PROBLEM 3 — INTERMEDIATE
Given this HTML: <ul id="menu"><li class="item active">Home</li><li class="item">About</li><li class="item active">Blog</li></ul>, write JavaScript that collects all li elements with the class active and removes the active class from each one.
PROBLEM 4 — APPLIED
You are building a quiz app. Each question is inside a <div class="question"> and the answer options are <button class="option"> elements inside that div. When the user clicks an option, you want to add the class selected to the clicked button and remove selected from any other button in the same question. Describe the selection strategy and write the code.
PROBLEM 5 — CRITICAL THINKING
A classmate writes this code to hide all paragraphs on the page: document.querySelector("p").style.display = "none"; They are confused because only the first paragraph disappears. Explain what went wrong, fix the code, and discuss whether there is ever a performance reason to prefer getElementById over querySelector for selecting by ID.

Lesson Summary

The Document Object Model (DOM) is a tree-shaped representation of every HTML element on the page. JavaScript uses querySelector to grab the first matching element and querySelectorAll to collect all matching elements into a static NodeList. Both accept any valid CSS selector — IDs with #, classes with ., tags by name, and complex combinators like "ul > li.active".

Always remember that querySelector returns null when nothing matches, so check before using the result. You can call these methods on any element — not just document — to perform scoped selections within a specific part of the page. Compared to older methods like getElementById and getElementsByClassName, querySelector and querySelectorAll are more flexible, more consistent, and the recommended approach for modern JavaScript development.

Varsity Tutors • Computer Programming 1 (JavaScript) • Selecting DOM Elements — querySelector / querySelectorAll