Other locators
When getByRole, getByLabel, getByText don't cut it — usually with legacy apps or unusual DOM structures — I reach for CSS pseudo-classes, XPath, layout-based selectors, or nth= indexing. These are escape hatches, not first choices. The most useful ones in practice: :has() to get a parent by child, :visible to filter hidden duplicates, and nth= to pick one from a list.
When I use these locators
The priority order: getByRole > getByLabel > getByText > getByTestId > everything in this file. I only reach for CSS/XPath when the preferred locators literally can't target the element — usually legacy apps without semantic HTML, or complex table/grid structures.
The two I use most often from this list: :has() to get a parent by child, and :visible to exclude hidden duplicates.
CSS locator — and Playwright's additions
Playwright's page.locator('css=...') accepts standard CSS selectors, but also adds pseudo-classes that don't exist in native CSS:
`:has-text()` — matches any element that contains the text somewhere inside (case-insensitive substring). Combine it with a tag or class to avoid matching the whole document. `:text()` — matches the smallest element containing the text. `:text-is()` — exact, case-sensitive text match. `:visible` — filters to only visible elements. Useful when there are hidden duplicate elements with the same selector.
Getting a parent element by its child
This is the most practical use case I have for CSS pseudo-classes. I have a list of items, each with a label and a button. I want to click the button in the row that has label 'Acme Corp'. The preferred way is locator.filter({ has: child }):
The CSS :has() pseudo-class does the same thing directly:
If neither works, xpath=.. as a last resort goes up one DOM level. Avoid it in stable tests — DOM structure changes will break it.
Layout-based locators
When an element has no unique attributes or text but is positioned relative to another element, I can use layout pseudo-classes. These work on pixel positions — not DOM structure.
I always combine layout pseudo-classes with a selector — using them alone often matches empty wrapper elements instead of the actual target.
nth= indexing and XPath
nth= picks a specific element by zero-based index from a locator result. Useful when there are multiple identical elements and I want a specific one by position.
XPath locators are the last resort. They work, but they're fragile — any DOM restructuring breaks them. I use XPath only when CSS approaches have failed.