JS Sketchbooksee JavaScript think ✏️
← back to phase 7

7.2 — Selecting elements

If this curriculum could teach you only one syntax for your future job, it would be this one. Automation testing is, hour by hour, the craft of pointing at elements — "click that button, assert that message" — and the pointing language is CSS selectors, spoken through querySelector.

Five forms cover the working day: tag, .class, #id, [attribute], and combinations with descent.

Playwright's locators accept this exact language — lesson 11.3's SelectorLab v2 is this lesson wearing a work badge. Learn it here where it's calm.

watch it happen
document.querySelector("li")
// first <li> in the tree

document.querySelectorAll("li.todo")
// ALL <li class="todo"> — a NodeList

document.querySelector("#items")
// the id — unique per page

document.querySelector("ul#items li.done")
// descent: a .done li INSIDE #items

document.querySelector("[data-test=submit]")
// by attribute — the tester's favorite

Form 1 — the bare tag: querySelector("li") walks the tree and returns the FIRST matching element (a live reference, 7.1).

litag name — every <li><h1>My List</h1><li class="todo">milk</li><li class="todo done">mom</li><button data-test="submit">the simplest selector: the tag itself — querySelector returns the FIRSTmatch
under the hood

The deeper story, with the real names for things — this part is what turns “I saw it” into “I can explain it.”

Why does JavaScript speak CSS here? Because stylesheets needed a "which elements does this rule hit" language first, and it was too good not to reuse — one grammar for styling, querying, and (in your future) locating.

Engines match selectors right to left: for "ul li.done" they find li.done candidates first, then verify a ul ancestor — exactly how you should read them too.

More grammar when you need it: ul > li (child only, no grandchildren), li:first-child / :nth-child(3) (position), [href^="https"] (attribute prefix).

Don't memorize the long tail — recognize it, and keep MDN's selector page bookmarked like every professional does.

And the career footnote: DevTools Console understands $('sel') and $$('sel') as shorthand for querySelector/All — the fastest way to TEST a selector against a live page before it goes in a script. You'll do this daily; start today, F12 on any site.

your turn

⌨️ build a tiny selector engine

Nothing demystifies selectors like implementing one. Given nodes as plain objects, write match(node, selector) for the three core forms — the same logic every browser runs a million times a day.

requirements:

  • Nodes look like { tag: "li", id: "top", classes: ["todo", "done"] }. Build an array nodes with: an h1 (id "title", no classes), a li with classes ["todo"], and a li with classes ["todo", "done"].
  • Write match(node, sel): if sel starts with # compare the id; if it starts with . check classes.includes; otherwise compare the tag.
  • Print how many nodes match ".todo", then how many match "li", then the id of the first "#title" match (use 4.10's find).

when you press RUN, the console must show exactly:

2
2
title

✏️ Quick check 1

Write the selector that finds elements carrying BOTH classes "card" and "active" on the same element:

✏️ Quick check 2

Write the selector for a <button> with attribute data-test="save":

✏️ Quick check 3

In "nav a.external" — what does the SPACE mean? Type one word: inside or sibling.

teach it back

🗣️ Now teach it back

Teach a friend the five selector forms with one example each — and explain why data-test attributes are the gold standard for automation, and what the space in a selector means.

Write it as if your friend is sitting next to you. Saved to your journal — future-you will use these notes to teach others.

a few sentences, minimum — you’ve got this
to remember
Five forms: tag · .class (chained = same element) · #id (unique) · [attr=value] · SPACE = descent (read right-to-left).
querySelector → first live match; querySelectorAll → NodeList of all (loop with for...of, spread with [...]).
data-test attributes = redesign-proof hooks made FOR tests. Try selectors live in DevTools with $() / $$() before scripting them.