
When building automation tests, one of the most crucial steps is identifying web elements buttons, fields, and links to interact with. This process is called locating, and the expressions used are locators.
In older frameworks like Selenium, locators often caused flaky tests and maintenance issues. Playwright, however, introduced a smarter approach with faster, stable, and adaptive locators that work seamlessly with modern web technologies like dynamic rendering, shadow DOMs, and single-page apps.
In this guide, you’ll learn:
How Playwright identifies elements
The differences between CSS, XPath, and Role-based locators
Real-world locator examples
Best practices for stability and speed
FAQs to deepen your understanding
A locator tells Playwright which element to interact with.
Definition:
A locator in Playwright is an object that represents a specific element (or group of elements) on a webpage, allowing you to perform actions such as click, type, or assert.
Example:
const { test, expect } = require('@playwright/test');
test('Locate element using CSS', async ({ page }) => {
await page.goto('https://example.com');
const heading = page.locator('h1');
await expect(heading).toHaveText('Example Domain');
});
Here,
page.locator('h1') identifies the element
expect(heading).toHaveText() verifies it
Playwright doesn’t immediately query the DOM when you define a locator. Instead, it resolves only when an action is performed.
This lazy evaluation provides key advantages:
Faster execution - fewer DOM lookups
Stability - automatic retries for delayed elements
Synchronization - handles dynamic content gracefully
Playwright’s auto-wait mechanism ensures elements are:
Present in the DOM
Visible and ready for interaction
Free from transitions or animations
This removes the need for hardcoded waits or sleep commands.
Playwright supports several locator strategies:
| Type | Example | Description |
|---|---|---|
| CSS Selector | 'button.login' |
Uses CSS rules to find elements |
| XPath Selector | '//input[@name="email"]' |
XML-style path queries |
| Text Locator | 'text=Submit' |
Finds elements by visible text |
| Role-based Locator | getByRole('button', { name: 'Login' }) |
Uses ARIA roles |
| Test ID Locator | getByTestId('signup-btn') |
Relies on custom attributes |
| Chain Locator | page.locator('div').locator('button') |
Targets nested elements |
Let’s explore each type in detail.
CSS Selectors are the most common and efficient way to locate elements.
Examples:
page.locator('input'); // by tag
page.locator('.login-btn'); // by class
page.locator('#username'); // by ID
page.locator('[placeholder="Email"]'); // by attribute
page.locator('form#login button'); // nested
Advantages:
Disadvantages:
May break if DOM structure changes
Best Practice:
Use data-testid for stability:
<button data-testid="submit-button">Submit</button>
page.locator('[data-testid="submit-button"]');
XPath allows querying XML-like structures in HTML.
Examples:
page.locator('//input[@id="email"]');
page.locator('//button[text()="Login"]');
page.locator('//div[contains(text(), "Welcome")]');
Pros:
✅ Works for complex DOMs
✅ Useful when CSS selectors aren’t available
Cons:
Slower and less readable
Sensitive to structural changes
Tip: Prefer CSS or Role-based locators unless XPath is necessary.
Role-based locators are one of Playwright’s most powerful features. They use accessibility roles and names for human-readable, stable tests.
Example:
await page.getByRole('button', { name: 'Login' }).click();
await page.getByRole('textbox', { name: 'Username' }).fill('admin');
Advantages:
✅ Readable and self-documenting
✅ Resistant to layout changes
✅ Encourages accessibility
Example HTML:
<button role="button" aria-label="Login">Sign In</button>
Locator:
page.getByRole('button', { name: 'Login' });
Use text locators for visible content on UI elements.
Examples:
page.locator('text=Submit').click();
page.locator('text=/login/i').click();
Pros:
✅ Easy for human readers
✅ Great for static UI text
Cons:
⚠️ Prone to failure if text changes
Use for visible, consistent text only.
For robust tests, use custom attributes like data-testid.
HTML Example:
<button data-testid="register-btn">Register</button>
Locator:
page.getByTestId('register-btn').click();
Why use them?
Independent of CSS or layout
Unaffected by UI redesigns
Ideal for long-term automation stability
Chaining helps target nested elements precisely.
Example:
await page.locator('form#signup').locator('button[type="submit"]').click();
Combined Example:
await page.getByRole('form').locator('input[type="email"]').fill('[email protected]');
This approach improves precision and clarity.
Once defined, locators can perform many actions:
| Action | Description |
|---|---|
.click() |
Clicks an element |
.fill() |
Types into inputs |
.check() |
Checks a checkbox |
.uncheck() |
Unchecks a checkbox |
.selectOption() |
Selects from dropdown |
.screenshot() |
Captures element image |
Example:
await page.locator('#username').fill('admin');
await page.locator('text=Submit').click();
Use assertions to verify UI state:
await expect(page.locator('h1')).toHaveText('Dashboard');
await expect(page.locator('.success')).toBeVisible();
Common Assertions:
toBeVisible()
toHaveText()
toBeChecked()
toHaveAttribute()
Assertions validate correctness not just automation flow.
| Feature | Locator | Element Handle |
|---|---|---|
| Lazy evaluation | ✅ | ❌ |
| Auto-waiting | ✅ | ❌ |
| Recommended | ✅ | ❌ |
Tip: Always use locators for modern Playwright tests.
| Mistake | Fix |
|---|---|
| Using absolute XPath | Prefer CSS or Role |
| Hardcoding text | Use data-test attributes |
| Not waiting for elements | Playwright auto-waits |
| Using handles directly | Use locators |
| Reusing old selectors | Update dynamically |
Following these fixes keeps your automation suite stable.
When locators fail, use Playwright’s debugging tools:
Run in Debug Mode:
npx playwright test --debug
Use Codegen:
npx playwright codegen https://example.com
Codegen records actions and generates locators automatically a time-saver for testers.
Playwright handles iframes and shadow DOMs effortlessly.
iFrame Example:
const frame = page.frame({ name: 'loginFrame' });
await frame.locator('#username').fill('demo');
Shadow DOM Example:
await page.locator('my-component').locator('button').click();
This makes Playwright ideal for modern, complex web apps.
Role-based locators promote accessibility and maintainability.
Example:
await page.getByRole('heading', { name: 'Dashboard' });
await page.getByRole('button', { name: 'Add New Item' }).click();
This method ensures your app is both accessible and automation-friendly — a win-win for QA and developers.
Best Practices:
Use specific locators (avoid wildcards)
Group actions logically
Avoid waitForTimeout()
Prefer data-testid attributes
Optimized locators can reduce execution time by up to 30%.
const { test, expect } = require('@playwright/test');
test('Signup form test', async ({ page }) => {
await page.goto('https://example-signup.com');
await page.getByRole('textbox', { name: 'Username' }).fill('newuser');
await page.locator('#email').fill('[email protected]');
await page.getByRole('textbox', { name: 'Password' }).fill('securePass123');
await page.locator('text=I agree to the Terms').click();
await page.getByRole('button', { name: 'Register' }).click();
await expect(page.locator('.success-message')).toHaveText('Registration Successful');
});
This combines CSS, role-based, and text locators for robust automation.
Locators form the backbone of Playwright automation.
Mastering them ensures:
Reliable and maintainable scripts
Faster test execution
Accessibility compliance
Reduced flakiness
Locator priority rule:
Role → CSS → Test ID → Text → XPath
Follow this order for stability and clarity.
Q1. Which locator type should I use?
Use role-based locators for accessibility; CSS selectors for general elements. Avoid XPath unless necessary.
Q2. How does Playwright’s auto-wait help?
It waits until the element is visible and ready, eliminating timing issues.
Q3. Can Playwright handle dynamic IDs?
Yes, use role-based or attribute locators instead of direct IDs.
Q4. Are role-based locators slower?
No they’re optimized and just as fast in most cases.
Q5. Do locators work with iframes and shadow DOMs?
Yes, Playwright supports both seamlessly.
Locators are the foundation of Playwright testing. By mastering CSS, Role-based, and Test ID locators, you can create automation scripts that are fast, stable, and future-proof.
To continue learning, explore [How to Write and Run Your First Test in Playwright] for setup guidance and [Playwright Test Configuration Explained] for mastering test environments and parallel runs.
Course :