assert_
glossary ↓ downloads
track: java · selenium
suite 03 · web fundamentals

CSS selectors

Web fundamentals15 min
as a manual tester

You'd describe an element to a colleague: 'the Login button, the blue one at the bottom of the form.'

in automation

A CSS selector is that description, written precisely enough that the browser finds exactly one element.

CSS selectors are patterns that match elements in the DOM. They're fast, readable, and the locator type you'll write most. Here's the whole practical toolkit, from most to least preferred:

selector cheatsheet
/* by id — the # sign. Best when available. */
#login-button

/* by class — the . sign (chain multiple, no spaces) */
.form_input
.input_error.form_input

/* by attribute — [name="value"] */
[data-test="username"]
input[placeholder="Password"]

/* by hierarchy — descendant (space) and direct child (>) */
form input          /* any input anywhere inside a form */
form > input        /* only inputs that are direct children */

/* by position — when there's truly nothing better */
.cart_item:nth-child(2)

/* partial attribute matches */
[id^="login"]       /* id starts with "login"  */
[id$="button"]      /* id ends with "button"   */
[class*="error"]    /* class contains "error"  */

Test selectors live — no code needed

DevTools is a selector playground. On saucedemo.com press F12 → Console tab, and use $$("…") (double dollar), which returns every element matching a CSS selector:

DevTools console
$$("#login-button")
$$(".form_input")
$$("[data-test='username']")
console output
> $$("#login-button")
[input#login-button.submit-button.btn_action]     // 1 match — perfect

> $$(".form_input")
[input#user-name.input_error.form_input, input#password.form_input]   // 2 matches

> $$("[data-test='username']")
[input#user-name.input_error.form_input]          // 1 match
$$('.form_input') in the Console — two matches returned and highlighted on hover
📷 screenshot slot — add images/devtools-console-matches.png
$$('.form_input') in the Console — two matches returned and highlighted on hover

The second technique you'll use forever: in the Elements panel, Ctrl+F opens a search box that accepts CSS selectors and shows "1 of N" — instantly telling you whether your selector is unique.

Practice without leaving the course: the locator sandbox two lessons ahead lets you type selectors against a live page and watch matches light up. Feel free to jump there and back.

What makes a selector good

A good locator is unique (matches exactly one element), stable (survives redesigns), and readable (the next person understands it). Priority order: iddata-test attribute → a meaningful class or attribute → hierarchy → position. Position (nth-child) is the last resort — it breaks the moment someone reorders the page.

Smell test: if your selector looks like div > div:nth-child(3) > span.x2a, it will break within a sprint. Go up the tree and find something with meaning.
⚠ when it breaks — the classics
$$ doesn't work in my code / script
Uncaught ReferenceError: $$ is not defined

Fix: $$() and $x() exist only in the DevTools Console — they're console utilities, not JavaScript. In Selenium you'll use By.cssSelector() instead.

The element is right there, but I get 0 matches
> $$("#user-name")
[]

Fix: Three usual suspects: a typo (ids are case-sensitive), the element lives inside an <iframe> (the console targets the top document — switch frames via the dropdown above the console), or the page re-rendered after you looked.

Console says my selector is invalid
Uncaught DOMException: Failed to execute 'querySelectorAll'… is not a valid selector

Fix: Usually XPath syntax fed to $$() (that's $x()'s job), or an unescaped special character. Check which dialect you're writing.

⚡ exercise · five selectors on saucedemo

Log in to saucedemo (user standard_user, password secret_sauce) to reach the Products page. Using Console $$() or Ctrl+F in Elements, write a selector for each — and verify the match count in brackets:

  1. The shopping cart icon (expect 1)
  2. All product "Add to cart" buttons (expect 6)
  3. All product names (expect 6)
  4. The product sort dropdown (expect 1)
  5. Only the "Sauce Labs Backpack" add-to-cart button (expect 1 — hint: its id)
show a solution
.shopping_cart_link
[data-test^="add-to-cart"]
.inventory_item_name
.product_sort_container
#add-to-cart-sauce-labs-backpack
key takeaways
  • # = id, . = class, [attr='value'] = attribute; space/> walk the hierarchy.
  • $$("selector") in the DevTools console and Ctrl+F in Elements test selectors instantly.
  • Good locators are unique, stable, readable — prefer id and data-test; avoid positional selectors.
← How a page is built — the DOM XPath — when CSS isn't enough →