Skip to main content

Complete Guide to Playwright Locators: CSS, XPath, getByRole & Best Practices (2026)

Complete Guide to Playwright Locators: CSS, XPath, getByRole & Best Practices (2026)

Reading Time: 15–20 Minutes

Focus Keyword: Playwright Locators

Category: Playwright Fundamentals




Introduction

Locators are the heart of Playwright automation.

Every action you perform in Playwright depends on locating elements correctly. Whether you're clicking a button, entering text, validating a message, uploading a file, or selecting a dropdown option, Playwright must first identify the correct element.

Many beginners spend weeks learning Playwright APIs but struggle with flaky tests because they don't understand locator strategies.

A strong locator strategy results in:

  • Stable automation
  • Faster execution
  • Easier maintenance
  • Better scalability

A poor locator strategy results in:

  • Random failures
  • Difficult debugging
  • Frequent maintenance
  • Low confidence in automation

In this guide, you'll learn Playwright Locators from beginner to advanced level, including interview questions, certification tips, and real-world examples.


What Is a Playwright Locator?

A Locator is Playwright's mechanism for finding elements on a webpage.

Example:

await page.locator('#login').click();

The locator tells Playwright how to find the element.

Unlike traditional automation tools, Playwright does not immediately capture the element. Instead, it stores instructions for locating the element whenever an action occurs.

Example:

const loginButton = page.locator('#login');

await loginButton.click();

Playwright searches for the button only when .click() executes.

This design makes Playwright significantly more reliable.


Why Locators Matter

Imagine you tell a friend:

"Meet me at the blue house."

Tomorrow the house gets painted white.

Your directions become useless.

The same thing happens with automation.

Bad Locator:

page.locator('.blue-button');

Developer changes:

.blue-button
↓
.green-button

Your test breaks.

Better Locator:

page.getByRole(
'button',
{ name:'Login' }
);

The button remains a button called Login, even if styling changes.


Locator Priority Pyramid

Microsoft recommends the following order:

  1. getByRole()
  2. getByLabel()
  3. getByPlaceholder()
  4. getByText()
  5. getByTestId()
  6. CSS Selectors
  7. XPath

Following this order improves stability and maintainability.


getByRole()

This is Playwright's most recommended locator.

Example:

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

Why?

Because Playwright uses accessibility information.

HTML:

<button>
Login
</button>

Accessibility Tree:

Role: Button
Name: Login

Playwright finds elements the same way assistive technologies do.

Common Examples:

Button

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

Link

page.getByRole(
'link',
{ name:'Forgot Password?' }
);

Checkbox

page.getByRole(
'checkbox',
{ name:'Remember Me' }
);

Textbox

page.getByRole(
'textbox',
{ name:'Email' }
);

Benefits:

  • Accessible
  • Stable
  • Readable
  • User-centric

getByLabel()

Ideal for forms.

Example:

await page.getByLabel(
'Email Address'
).fill(
'admin@test.com'
);

HTML:

<label>Email Address</label>
<input type="email">

Advantages:

  • Stable
  • Accessible
  • Easy to understand

Common Use Cases:

  • Login Forms
  • Registration Forms
  • Checkout Forms
  • Search Forms

getByText()

Finds elements using visible text.

Example:

await page.getByText(
'Sign In'
).click();

Advantages:

  • Simple
  • Beginner-friendly

Disadvantages:

  • Text changes frequently
  • Translation issues
  • Marketing changes

Best Use Cases:

await expect(
page.getByText(
'Order Created Successfully'
)
).toBeVisible();

Use it primarily for validation rather than actions.


getByPlaceholder()

Example:

await page.getByPlaceholder(
'Enter Email'
).fill(
'admin@test.com'
);

HTML:

<input placeholder="Enter Email">

Useful when labels don't exist.

However, labels are generally preferred.


getByAltText()

Used for images.

Example:

await page.getByAltText(
'Company Logo'
);

HTML:

<img
src="logo.png"
alt="Company Logo">

Useful for:

  • Logos
  • Image Links
  • Icons

getByTitle()

Example:

await page.getByTitle(
'Close Dialog'
);

HTML:

<button title="Close Dialog">
X
</button>

Useful for:

  • Tooltips
  • Close Buttons
  • Menu Icons

getByTestId()

Enterprise favorite.

HTML:

<button
data-testid="login-btn">
Login
</button>

Playwright:

await page.getByTestId(
'login-btn'
).click();

Advantages:

  • Extremely stable
  • Survives redesigns
  • Independent of text

Disadvantages:

  • Requires developer support
  • Not user-focused

CSS Selectors

Example:

page.locator('#username');

Class:

page.locator('.btn-primary');

Attribute:

page.locator(
'[type="submit"]'
);

Advantages:

  • Flexible
  • Familiar
  • Powerful

Disadvantages:

  • Break during redesigns
  • Dependent on implementation

XPath Selectors

Example:

page.locator(
'//button[text()="Login"]'
);

Pros:

  • Extremely powerful

Cons:

  • Hard to read
  • Difficult to maintain
  • Fragile

Recommendation:

Use XPath only when necessary.


Locator Chaining

Example:

const form =
page.locator('#login-form');

await form
.getByRole(
'textbox',
{ name:'Email' }
)
.fill('user@test.com');

Benefits:

  • Better precision
  • Reduced ambiguity
  • Improved reliability

Filtering Locators

Example:

page.getByRole(
'listitem'
)
.filter({
hasText:'Product A'
});

Useful for:

  • Product Cards
  • Tables
  • Lists

Strict Mode Explained

Playwright refuses to guess.

Example:

page.locator('.product').click();

If multiple elements match:

Strict Mode Violation

Fix:

page.locator('.product').first();

or

page.locator('.product').nth(2);

first(), last(), nth()

First

page.locator('.product').first();

Last

page.locator('.product').last();

Specific

page.locator('.product').nth(2);

Useful for repeated elements.


Dynamic Elements

Bad:

page.locator(
'#btn_12345'
);

Tomorrow:

#btn_98765

Broken.

Better:

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

Stable.


Frame Locators

Payment pages often use iframes.

Example:

const frame =
page.frameLocator(
'#payment-frame'
);

await frame
.getByRole(
'button',
{ name:'Pay Now' }
)
.click();

Used in:

  • Stripe
  • PayPal
  • Embedded Widgets

Real E-Commerce Example

Search Product:

await page
.getByPlaceholder(
'Search Products'
)
.fill(
'Wireless Mouse'
);

Search:

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

Validate:

await expect(
page.getByText(
'Wireless Mouse'
)
).toBeVisible();

Interview Questions

Which locator does Playwright recommend?

Answer:

getByRole()

What is Strict Mode?

Playwright throws an error when multiple elements match a locator.

Difference Between Locator and ElementHandle?

Locator:

  • Dynamic
  • Auto Waiting
  • Re-evaluated

ElementHandle:

  • Static Snapshot
  • Can Become Stale

Why avoid XPath?

Maintenance complexity and fragility.

What is getByTestId()?

Locator using dedicated testing attributes.


Certification Notes

Remember:

getByRole()
getByLabel()
getByText()
getByPlaceholder()
getByAltText()
getByTitle()
getByTestId()

Also:

first()
last()
nth()
count()
filter()

These frequently appear in Playwright interviews and certification exams.


Best Practices

Always:

  • Prefer getByRole()
  • Use getByLabel() for forms
  • Use getByTestId() for complex components
  • Chain locators when possible
  • Use filtering for repeated elements

Avoid:

  • Dynamic IDs
  • Deep XPath
  • nth-child selectors
  • Overusing getByText()

Conclusion

Locators are the foundation of every Playwright framework.

Mastering them improves:

  • Stability
  • Reliability
  • Maintainability
  • Automation Success

Start with:

getByRole()
↓
getByLabel()
↓
getByTestId()

Avoid:

Fragile XPath
Dynamic IDs
Deep CSS Chains

A strong locator strategy will save hundreds of hours of maintenance and make your automation framework far more reliable.


About Bugged But Happy

Bugged But Happy

Learning, Testing, and Growing One Bug at a Time.

Practical Playwright tutorials, automation testing guides, interview preparation resources, certification tips, and real-world testing insights.

https://thebuggedbuthappy.blogspot.com/


Comments

Popular posts from this blog

Selenium 5: What’s New and Why It Still Matters in 2025

Selenium 5: What’s New and Why It Still Matters in 2025 data-full-width-responsive="true"> Selenium has been the backbone of web automation testing for over a decade. From the early days of Selenium RC to WebDriver and the release of Selenium 4, it has enabled QA engineers worldwide to automate browsers reliably. But as modern frameworks like Playwright and Cypress gained attention, critics started asking: “Is Selenium dead?” In 2025, the answer is clear: Selenium is not dead — it has evolved. With the release of Selenium 5 , the project has modernized to support new browser technologies, improve stability, and remain a cornerstone of test automation strategies. 1. Introduction — Selenium’s Legacy Selenium started in 2004 as a tool to automate browsers for functional testing. Over the years: Selenium RC gave way to Selenium WebDriver. Selenium Grid enabled parallel execution at scale. Selenium 4 introduced W3C WebDriver com...

Google Anti-Gravity Thinking in Software Testing (With Real-World Examples & Tools)

Google Anti-Gravity Thinking in Software Testing A practical mindset that prepares testers to break systems the right way Software testing is often taught as a structured activity. Write test cases. Follow steps. Verify expected results. Mark Pass or Fail. This works well in training environments — but real users don’t behave this way. They don’t read requirements. They don’t follow flows. They don’t wait patiently. They click early. They click repeatedly. They lose network. They rotate screens. They refresh pages. And when this happens, many applications fail silently. That is why production bugs exist. To catch these bugs early, testers must think differently. They must think beyond rules. They must think beyond assumptions. This is where Anti-Gravity Thinking becomes powerful. What Is Anti-Gravity Thinking in Testing? Google Anti-Gravity is a visual experiment where UI elements do not stay fixed. They float. They move. They fall out of place. In...

Chaos Testing for Automation Engineers

Chaos Testing for Automation Engineers Why automation passes in CI but fails in production ⏱ Reading time: 10–12 minutes Most automation engineers have experienced this moment: All test cases are green. Pipelines are passing. Confidence is high. And then production fails. This blog explains why that happens — and how Chaos Testing , inspired by Anti-Gravity thinking, helps automation engineers test reality instead of assumptions. Why Automation Testing Often Gives False Confidence Automation scripts usually validate: Stable environments Correct inputs Predictable flows Fast responses But real systems don’t behave this way. Production systems face: Network delays Service timeouts Partial failures Unexpected user behavior Chaos Testing exists to simulate these conditions intentionally — before users experience them. What Is Chaos Testing (In Simple Terms) Chaos Testing is n...