How to Use Playwright Locators in 2026

Master Playwright locators, enhance test stability, and improve accessibility with efficient locator strategies and modern testing practices.

Last updated: 21 August 2026 16 min read

Key Takeaways

  • Playwright locators help testers identify and interact with web elements reliably, with built-in strategies such as getByRole(), getByLabel(), getByText(), and getByTestId() that make tests more readable and less dependent on changing DOM structures.
  • Choosing the right locator improves test stability and maintainability. User-facing locators should generally be preferred over CSS or XPath, while chaining and filtering can help precisely target elements in complex or repeated UI components.
  • Reliable locators work best when combined with Playwright's synchronization and debugging capabilities. Auto-waiting, Codegen, and Inspector help create and troubleshoot locators while cross-browser execution helps validate that tests remain reliable across different environments.

For a UI test to work properly, testers have to verify whether web components work on a live web browser.

Playwright locators help you interact with web elements to know how they look and behave in the live testing environment.

Playwright locators have evolved to offer developers powerful tools to create efficient, reliable, and accessible tests. By using advanced locator strategies, you can ensure tests remain resilient and scalable, even if web apps grow more complex.

This guide explores how to use Playwright locators, including best practices, advanced techniques, and new tools like AI-driven automation to streamline test creation and maintenance.

What are Playwright Locators?

Playwright locators are a higher-level abstraction over traditional selectors like CSS and XPath, providing a stable and readable way to find and interact with web elements during UI testing. They can be used to fetch values, perform actions, and automate interactions across browsers.

Playwright locators serve as a higher-level abstraction over traditional selectors like CSS or XPath, enabling more stable and readable tests.

Example of Playwright Locator

A test may need to click a Submit button, fill in a Password field, or verify that a confirmation message appears.

They are more than just a way to find an element. Playwright uses them as part of its auto-waiting behavior and retry logic, while also supporting various filtering and chaining actions.

This means when your test clicks, types, or checks something, Playwright first looks for the element and waits until it’s ready to interact (like visible and enabled), instead of using manual delays like waitforTimeout() before every action.

await page. getByRole('button', { name: 'Submit' }). click();

await page. getByLabel('Password'). fill('password123'); 

await expect(page.getByText('Payment successful')). toBeVisible();

Output –

example of playwright locator

This is particularly useful for modern applications where the DOM can change after a page rendering or reloading.

If an application re-renders an element between locator actions, Playwright can resolve the locator again against the updated DOM instead of relying on an old element reference.

Locator Types in Playwright

Playwright provides several built-in locators for identifying elements according to their role, text, labels, attributes, and other user-facing characteristics.

Playwright recommends prioritizing user-facing locators and explicit testing contracts when possible. The main locator types are

1. getByRole()

getByRole() locates an element according to its ARIA role and accessible name. It is generally the preferred choice for interactive elements because it reflects how users and assistive technologies perceive the page.

For example, consider a login button:

await page. getByRole('button', { name: 'Sign in' }). click();

Here, the button identifies the element’s role, while Sign In identifies its accessible name.

Using the name makes the locator more precise when several buttons exist on the page.

await page. getByRole('button', { name: 'Save' }). click();

If the page contains multiple Save buttons, scope the locator to the relevant section instead of relying on its position in the DOM.

const settings = page. getByRole('dialog', { name: 'Settings' }); 

await settings. getByRole('button', { name: 'Save' }). click();

This approach makes the locator describe the user’s interaction with the page rather than the page’s underlying structure.

Output –

getbyrole and scoped locators

2. getByText()

getByText() locates an element using its visible text.

await expect(page.getByText('Payment successful')). toBeVisible();

It is useful when the text itself is the most meaningful way to identify non-interactive content such as messages, headings, or paragraphs.

For interactive elements such as buttons and links, Playwright recommends using role locators when possible.

You can also use exact matching when similar text appears in multiple places:

await page. getByText('Payment successful', { exact: true }). click();

Text matching normalizes whitespace, so the locator does not depend on every space or line break appearing exactly as it does in the source HTML.

Output –

getbytext visible and exact match

3. getByLabel()

getByLabel() is designed for form controls associated with a label. It works well for input fields such as textboxes, checkboxes, and radios that are properly labelled with HTML tags.

For example,

await page. getByLabel('Email address'). fill('user@example.com'); 

await page. getByLabel('Password'). fill('password123');

Output –

getbylabel form controls

4. getByPlaceholder()

getByPlaceholder() identifies an input through its placeholder.

await page. getByPlaceholder('Search products'). fill('laptop');

This can be useful for search fields and inputs where the placeholder clearly identifies the field.

However, placeholders are part of the interface copy and can change as the design evolves. If the field has a stable accessible label, getByLabel() is generally a stronger choice.

Output –

getbyplaceholder search field

5. getByAltText()

getByAltText() locates an element using its text alternative.

await page. getByAltText('Company logo'). click();

This is useful for images and other elements that support alternative text.

Using meaningful alternative text also gives the test a relationship to an accessibility attribute rather than to an implementation detail such as an image filename or CSS class.

Output –

getbyalttext image locator

6. getByTitle()

getByTitle() locates an element using its title attribute.

await expect(page.getByTitle('Issues count')). toHaveText('25 issues');

Use it when the title attribute provides a stable and meaningful way to identify the element.

Output –

getbytitle issues count

7. getByTestId()

getByTestId() locates an element using a test-specific identifier.

await page. getByTestId('checkout-button'). click();

A test ID can be useful when the element does not have a suitable role, accessible name, or other stable user-facing attribute. For example,

<button data-testid="checkout-button"> Continue </button>

Test IDs are not user-facing. They are an explicit contract between the application and the test suite. This makes them useful when a dedicated testing hook is more stable than visible text or other UI attributes.

Output –

getbytestid explicit contract

8. page.locator()

page.locator() can be used with CSS or XPath selectors.

await page. locator('button'). click();


Or

await the page. locator('//button'). click();

CSS and XPath are supported by Playwright, but they should generally be a fallback when a more user-facing or explicit locator is not suitable.

Output –

page locator css xpath fallback

Core Locator Syntax & Options

Once you have chosen the appropriate locator type, you can use its syntax and available options to make the locator more precise.

The basic syntax is

const element = page. getByRole('button', { name: 'Submit' });

The first argument identifies what you are looking for, while the options object can provide additional criteria for matching the element.

For example, getByRole() supports options such as name, checked, disabled, expanded, selected, level, and includeHidden. These options are specific to the locator API and should not be treated as generic options available to every locator.

1. getByRole()

OptionWhat it doesExample
nameMatches the element’s accessible namegetByRole(‘button’, { name: ‘Save’ })
checkedMatches checked or unchecked controlsgetByRole(‘checkbox’, { checked: true })
disabledMatches enabled or disabled elementsgetByRole(‘button’, { disabled: true })
expandedMatches expanded or collapsed elementsgetByRole(‘button’, { expanded: true })
selectedMatches selected elementsgetByRole(‘option’, { selected: true })
levelTargets a specific heading levelgetByRole(‘heading’, { level: 2 })
includeHiddenIncludes elements that are normally excluded from role matchinggetByRole(‘button’, { includeHidden: true })

For example, if a page contains multiple checkboxes, you can use the checked option to target one based on its current state:

await page. getByRole('checkbox', {

name: 'I agree to the terms', 

checked: true

 }).click();

Similarly, the level option can help identify a specific heading:

await expect(

  page. getByRole('heading', { name: 'Payment details', level: 2 })

).toBeVisible();

You can then perform an action on the locator:

await element. click();

Or use it in an assertion:

await expect(element). toBeVisible();

The same locator can be reused for multiple actions:

const submitButton = page. getByRole('button', { name: 'Submit' }); 

await expect(submitButton). toBeVisible(); 

await submitButton. click();

Output –

getbyrole options and reuse

The playwright resolves the locator against the current page when an action is performed. This allows the locator to work with pages whose DOM is updated or re-rendered during a test.

When a locator matches more than one element, you can make it more precise using chaining and filtering. These techniques are covered in the next section.

2. Chaining and filtering locators”Addcart”

Sometimes a locator is not specific enough by itself. Consider a product listing with multiple Add to cart buttons:

<li>

  <h3>Wireless Mouse</h3>

  <button>Add to cart</button>

</li>

<li>

  <h3>Keyboard</h3>

  <button>Add to cart</button>

</li>

This locator could match more than one button:

page.getByRole('button', { name: 'Add to cart' });

Instead, first locate the relevant product and then find the button inside it:

const product = page

  .getByRole('listitem')

  .filter({ hasText: 'Keyboard' });

await product

  .getByRole('button', { name: 'Add to cart' })

  .click();

Output –

chaining and filtering locators

Playwright supports chaining and filtering locators by text and by the presence of another locator. Locators can also be chained to narrow the search to a particular part of the page.

Filtering with hasText

For example:

const product = page

  .getByRole('listitem')

  .filter({ hasText: 'Keyboard' });

This first identifies the product item and then narrows the result to the item containing the specified text.

Filtering with another locator

You can also filter based on whether an element contains another element:

const product = page

  .getByRole('listitem')

  .filter({

    has: page. getByRole('heading', { name: 'Keyboard' })

  });

This is useful for repeated components where visible text alone may not provide enough context.

Chaining locators

You can also create a locator for a container and then locate an element inside it:

const dialog = page. getByRole('dialog', { name: 'Settings' });

await dialog

  .getByRole('button', { name: 'Save' })

  .click();

Output –

filtering with has and container chaining

The result is more specific without requiring a long CSS or XPath expression.

Best Practices for Creating Resilient Locators

Creating resilient locators ensures your Playwright tests remain stable and reliable, even as your application’s UI evolves. Here are the best practices to follow:

  • Prioritize Semantic HTML and ARIA Roles: Use native HTML elements (e.ge.g., <button>, <input>, <a>) and their corresponding ARIA roles (e.g., button, textbox, link). This leads to more stable locators that reflect real user interactions and ensures your tests align with accessibility standards.
  • Use Accessible Names: Always provide meaningful accessible names through visible text, aria-label, or aria-labelledby. This makes locators more precise and accessible, improving both test reliability and usability for assistive technologies.
  • Combine Role and Name for Precision: When targeting elements, combine the role with the name (e.g., getByRole(‘button’, { name: ‘Submit’ })). This ensures you’re selecting the correct element, especially in cases where multiple elements share the same role.
  • Avoid Using Structural Selectors: Steer clear of relying on CSS classes or XPath that are dependent on the DOM structure, as these can easily break when the UI is updated. Instead, use semantic locators such as getByRole, getByLabel, or getByText for better stability.
  • Leverage Auto-Waiting Features: Playwright’s locators automatically wait for elements to be visible and interactable. Avoid manual waits (e.g., waitForTimeout) and let Playwright handle synchronization to ensure your tests are more stable and faster.
  • Use Chaining and Nested Locators: Chain locators to refine your element selection in complex UIs. For example, locate a button within a modal or a specific section to avoid selecting the wrong element. This reduces ambiguity and makes tests more context-specific.
  • Keep Locator Names Consistent: Use a consistent naming convention across your test suite. This helps avoid confusion and ensures that your locators remain easy to maintain and update over time.
  • Refactor Locators When Necessary: As your app evolves, periodically revisit and refactor your locators. Keep them as simple as possible while ensuring they are robust enough to handle minor UI changes.
  • Test for Accessibility: Adopt an accessibility-first approach to locators. Using roles and accessible names not only ensures your tests are more stable but also improves the accessibility of your application, benefiting users with disabilities.

Using Playwright’s Codegen and Locator Inspector

You do not always have to write every locator from scratch.

Playwright’s Codegen can observe interactions in a browser and generate test code. Its locator generator prioritizes role, text, and test ID locators and can refine a locator when multiple elements match.

How to use Codegen

Simply run the Playwright Codegen command, and it will launch the browser, allowing you to record interactions like clicks, typing, and navigation. Playwright generates the corresponding test code as you interact with the page.

npx playwright codegen

You can also provide a URL:

npx playwright codegen https://example.com

After opening the page, interact with the element you want to test. Playwright generates the corresponding locator and test code.

For example, it may generate:

await page. getByRole('button', { name: 'Sign in' }). click();

Codegen is useful for getting started, but generated code should still be reviewed.

Ask:

  • Is this the most meaningful locator for the element?
  • Does it depend on text that changes frequently?
  • Would a test ID provide a stronger testing contract?
  • Is the locator unnecessarily specific?
  • Does it uniquely identify the intended element?

Treat Codegen as a starting point rather than a replacement for locator design.

How to Use Playwright Inspector

When a locator does not behave as expected, Playwright Inspector can help you inspect and refine it.

The Inspector allows you to pick an element, see the locator generated for it, and edit the locator while seeing which element it matches in the browser.

You can start debugging with:

npx playwright test --debug

You can then use the Pick Locator functionality to identify an element and experiment with the locator.

This is particularly useful when:

  • multiple elements match the same locator;
  • The locator is not finding the expected element
  • A locator works on one page state but not another;
  • A dynamic component has several similar controls;
  • You need to decide between a built-in locator and a CSS/XPath selector.

The goal is not simply to find a selector that works once. Use the Inspector to understand why the locator matches the element and whether that relationship is stable enough for the test.

Handling Dynamic and Asynchronous UI

Handling dynamic and asynchronous elements is crucial in modern web applications, where content may change or load dynamically. Playwright offers several strategies to ensure your tests remain stable when interacting with such elements.

  • Auto-Waiting: Playwright automatically waits for elements to become visible, stable, and interactable. This built-in auto-waiting feature reduces the need for manual waits or timeouts, ensuring your tests synchronize with the page’s loading state.
  • Using waitFor Methods: For more control, Playwright provides waitForSelector() and other waitFor methods, allowing you to explicitly wait for elements to appear or become ready before interacting with them.
  • Handling Delayed or Lazy-Loaded Content: If your application loads content asynchronously (e.g., infinite scrolling, AJAX requests), use waitForResponse() or waitForRequest() to wait for network responses before interacting with elements.
  • Dealing with Animations: For pages with animations or transitions, use waitForTimeout() or wait for the animation to complete using appropriate selectors to ensure the element is in the desired state.
  • Handling Element Visibility: Use Playwright’s isVisible() method to check if an element is visible before performing actions on it. This is useful for handling elements that appear or disappear based on user interactions or page changes.

Accessibility-first Locator Strategy

Playwright’s role and accessible-name locators create a useful connection between UI testing and accessibility.

Consider:

await page. getByRole('button', { name: 'Submit' }). click();

This locator relies on information that describes how the control is exposed to users and assistive technologies. Playwright recommends role locators because they are close to how users and assistive technology perceive the page.

However, using accessibility-oriented locators does not replace accessibility testing. A test can successfully locate a button while the application still contains other accessibility issues.

For example, a locator may confirm that a button can be identified by its accessible name, but that does not by itself establish full WCAG conformance.

For broader accessibility coverage, teams can complement functional Playwright tests with dedicated web accessibility testing across real browsers and devices. BrowserStack Accessibility Testing supports automated, assisted, and manual accessibility testing workflows.

Conclusion

Playwright locators provide a way to identify web elements based on how they are presented in testing.

The right locator depends on the element and testing requirement. Start with user-facing locators, narrow down options using chaining and filtering, and use CSS or XPath along with Playwright locators to build test stability.

As applications become more dynamic, letting Playwright handle actionability and synchronization can further reduce unnecessary waits and brittle test logic.

Once you master locators, validate your test suites across multiple devices and browsers. Running Playwright tests across broader browser coverage with BrowserStack Automate can help teams identify environment-specific failures and scale execution as test coverage grows.

Version History

  1. Aug 19, 2026 Current Version

    Updated locator types, syntax, filtering techniques, and strategies for creating resilient locators.

    Venkatesh Raghunathan
    Reviewed by Venkatesh Raghunathan Full Stack Software Developer
Tags
Automation Testing Real Device Cloud Website Testing
Grandel Robert
Grandel Robert

Senior Automation Expert

Grandel D'Souza is a software quality and test automation professional with 8+ years of experience in quality engineering and software testing. He specializes in building scalable automation solutions and helping teams improve software reliability, release velocity, and testing efficiency.

FAQs

Use stable user-facing attributes, combine roles with accessible names, scope repeated elements through chaining and filtering, and avoid unnecessary CSS/XPath or fixed timeouts. Use Playwright Codegen and Inspector to create and debug locators when needed.

Yes. Playwright supports both CSS and XPath through the page. locator(). However, long or structure-dependent selectors can be harder to maintain when the DOM changes, so built-in user-facing locators are generally preferred when suitable.

Use user-facing locators such as getByRole(), getByLabel(), or getByText() when they provide a clear and stable way to identify an element. Use getByTestId() when an explicit testing contract is more appropriate, and CSS or XPath as a fallback.

Playwright locators are functions used to identify and interact with web elements during automated UI testing. They support actions such as clicking, filling fields, and verifying element states.

Automation Tests on Real Devices & Browsers
Seamlessly Run Automation Tests on 3500+ real Devices & Browsers