Recommended Free Tools
iTechGuides is reader-supported. When you buy through links on our site, we may earn an affiliate commission. As an Amazon Associate I earn from qualifying purchases. Learn more
Build reusable Playwright locators from user-facing meaning, then scope them to the component or item you intend to act on. Put repeated interactions behind a page object or component helper, and use custom selector engines only when a recurring need justifies the extra layer. This design makes targets clearer and easier to maintain; Playwright’s documentation describes the locator mechanisms but does not quantify a reduction in test flakiness.
What makes a Playwright locator reusable and stable?
A reusable locator captures a meaningful way to identify an element and can be applied wherever the same page behavior occurs. Prefer locators based on what a user or assistive technology can perceive: an interactive control’s role and accessible name, or a form field’s label. For example, getByRole('button', { name: 'Save' }) expresses the intended control more clearly than a selector tied to its current CSS classes.
Playwright calls locators “the central piece of Playwright’s auto-waiting and retry-ability.” Locator actions resolve against the current DOM, which helps when a page rerenders between actions. It does not make an ambiguous locator safe: an action that matches multiple elements is strict and fails rather than choosing one for you. Playwright’s locator documentation explains these behaviors.
Choose the locator that expresses the contract
| Approach | Use it when | Stability consideration |
|---|---|---|
| Role and accessible name | The target is an interactive control whose user-facing role and name identify it, such as a button named “Save.” | Expresses user-visible meaning; keep accessible names clear and distinctive. |
| Label | The target is a form control with a label, such as an email field. | Connects the locator to the field’s user-facing label. |
| Test ID | The team wants an explicit testing contract and text or role is not the behavior under test. | It is not user-facing; its durability depends on the team maintaining the contract. |
| CSS or XPath | A specific implementation detail is necessary and the selector can be kept short and justified. | Selectors tied to DOM structure can break when markup changes. Playwright cautions that XPath is tied to implementation structure and may be less reliable as the DOM changes. |
| Custom selector engine | A demonstrated, recurring domain-specific selection need merits a shared extension. | Registration is supported, but an extension layer is not inherently more stable than built-in semantic locators and must be maintained. |
See Playwright’s best practices for guidance on user-visible behavior and resilient locator APIs, and its discussion of other locators for the caveat about XPath.
#1 Best Overall
Scope repeated controls to the right item
When a page repeats the same action—such as a button on every product card—identify the card first, then find its button. A semantic container plus a distinguishing heading makes the target understandable and avoids relying on list position.
const productCard = page.getByRole('listitem').filter({ has: page.getByRole('heading', { name: 'Wireless Keyboard' }) });
const saveButton = productCard.getByRole('button', { name: 'Save' });
await saveButton.click();
The has filter is evaluated relative to each original locator match: its inner locator must match within that candidate item. If more than one card can have the same heading, add a meaningful discriminator rather than silently selecting the first. The locator guide covers chaining and filtering.
Rank #2
Make reuse visible in a page object or component helper
Centralize repeated selectors and actions where they represent meaningful page behavior. A page object can provide a named method for finding a product card or saving it, while a component helper can accept a scoped Locator when the same component appears on multiple pages. This keeps tests focused on actions and intent instead of repeating selector construction.
PC Slower Than It Used to Be?
A free scan shows the junk files, broken settings and background clutter dragging Windows down - then fixes them in one click.Free scan · Windows 10 & 11Crashes, No Sound, or Screen Glitches?
Random freezes, missing sound and display glitches usually trace back to one bad driver. Find and replace yours safely.Free scan · under a minuteimport { Page, Locator } from '@playwright/test';
class ProductCard {
constructor(private readonly root: Locator) {}
saveButton() {
return this.root.getByRole('button', { name: 'Save' });
}
async save() {
await this.saveButton().click();
}
}
class ProductsPage {
constructor(private readonly page: Page) {}
product(name: string) {
const root = this.page.getByRole('listitem').filter({
has: this.page.getByRole('heading', { name })
});
return new ProductCard(root);
}
}
Here the abstraction accepts the product name but keeps the actual selection semantic and scoped. Adapt the locator roles and names to the page’s accessible structure. Avoid turning the helper into a collection of opaque selector strings; a useful abstraction makes the behavior and target easier to understand. Playwright’s page-object documentation demonstrates selector encapsulation and reusable page-object code.
Handle ambiguity instead of hiding it
If a locator matches multiple elements, improve its context or identifying details. Routine use of first(), last(), or nth() can make a test pass while pointing at a different element after the page changes. Positional selection is appropriate only when position is itself part of the intended behavior and is stable by design.
- Scope the search to a meaningful region, such as a named dialog or product card.
- Use a distinguishing accessible name, label, heading, or maintained test ID.
- Where ambiguity is plausible, assert that the locator identifies one element before acting; treat a failed uniqueness check as a cue to clarify the target.
Playwright’s locator actions are strict when multiple elements match. The locator documentation describes strictness and the available locator APIs: Locators.
Rank #4
When should you register a custom selector engine?
Playwright supports custom selector engines through selectors.register(). That extension point is useful when a repeated selection rule genuinely needs a shared, domain-specific implementation. It is not a stability shortcut: registration adds a layer the team must understand and maintain, and it does not make a selector more robust than a built-in locator by itself.
Start with role, label, text, or a test ID and the built-in chaining and filtering APIs. Consider a custom engine only if that approach leaves a recurring need that cannot be expressed clearly. See Playwright’s extensibility documentation for the registration mechanism.
Quick Recap
A practical review checklist
- Does the locator describe the user-visible target or an intentionally maintained test contract?
- Does it identify exactly the intended element in the relevant page context?
- Does it avoid unnecessary dependence on CSS classes, DOM nesting, or position?
- Does any reusable helper expose meaningful page behavior rather than hiding selector logic?
- Is a custom selector engine solving a demonstrated repeated need rather than replacing built-in locators by default?
Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.

