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:
- getByRole()
- getByLabel()
- getByPlaceholder()
- getByText()
- getByTestId()
- CSS Selectors
- 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
Post a Comment