Reference · Cheat Sheet

Playwright Selectors / Locators

How to point at an element so your test survives a UI redesign. Source of truth for every lesson.

Priority order — pick the highest one that works

Playwright's official recommendation: prefer how a human perceives the element. Drop down the list only when you must.

#LocatorTargetsExampleTier
1getByRoleButtons, links, checkboxes, headings, inputs — by their accessibility role + namegetByRole('button', {name:'Subscribe'})prefer
2getByLabelForm fields, via their <label> textgetByLabel('Email address')prefer
3getByPlaceholderInputs with placeholder text (when no label)getByPlaceholder('you@example.com')ok
4getByTextNon-interactive content: messages, paragraphs, spansgetByText('You are subscribed')ok
5getByAltText / getByTitleImages by alt text; elements by title attributegetByAltText('Company logo')ok
6getByTestIdAnything — via an explicit data-testid you addgetByTestId('signup-submit')fallback
✗CSS / XPathRaw DOM paths like .card > form > button:nth-child(3)locator('div.card button')avoid

Why this order? Role/label/text mirror what the user actually sees, so they survive restyling and DOM restructuring. CSS/XPath are tied to structure — a redesign silently breaks them. data-testid is the resilient escape hatch when nothing user-facing is unique.

Good vs. brittle — same button

✓ Resilient

getByRole('button',
  { name: 'Subscribe' })

Survives moving the button, restyling, wrapping it in new divs.

✗ Brittle

locator(
  'div.card > form > button')

Breaks the instant someone adds a wrapper or renames a class.

Adding a test ID (the fallback)

When an element has no unique role/label/text, add an explicit hook in your markup:

<button type="submit" data-testid="signup-submit">Subscribe</button>

…then target it with getByTestId('signup-submit'). It's a contract: "tests depend on this id — don't rename it casually."

Talking to Claude: you rarely type these yourself early on. You say "click the Subscribe button" and Claude chooses a locator. The payoff of knowing this sheet: you can review Claude's choice ("use the button's role, not a CSS path") and you'll write better tests when you start saving them.

The accessibility connection

Notice the top locators are all accessibility concepts (role, label, alt text). That's not a coincidence — Playwright reads the same accessibility snapshot Claude uses. Bonus: writing testable markup (real <label>s, proper button roles) also makes your app more accessible to screen-reader users. Good tests and good a11y push the same direction.