Mastering Playwright Locators & Selectors: Complete Guide
Discover how to locate elements in Playwright. Review code examples for getByRole, getByText, custom CSS/XPath overrides, and locating nested structures.
playwright-v1-49-matrix
Mastering Playwright Locators & Selectors: Complete Guide
Locators represent the core building blocks of test scripts in Playwright. They resolve UI elements dynamically during execution. This guide explains how to construct resilient locators that resist layout shifts and pipeline flakiness.
Introduction
Older automation tools relied on static CSS paths or raw XPath strings. These selections break easily when developers update classes or wraps. Playwright solves this issue with web-first locators that auto-wait for actions and target semantic roles.
Using role-based locators guarantees your tests interact with the page exactly like human users, improving accessibility and reliability.
The Locators Architecture
Playwright locators do not store pointers to elements. Instead, they act as search configurations that resolve fresh matching nodes on the page every time an action executes:
graph TD
LocatorDef["Define: page.getByRole('button')"] --> ActionTrigger["Action: click()"]
ActionTrigger --> AutoWait["Auto-Wait: Element is Visible, Enabled, Stable"]
AutoWait --> ResolveDOM["Query DOM: Locate Matching Node"]
ResolveDOM --> ExecuteAction["Action Executed on Node"]This dynamic search structure avoids stale element reference errors.
Locators Lifecycle Sequence
Every locator interaction triggers a sequence of checks before performing mouse or keyboard events:
sequenceDiagram
participant Test as Test runner
participant Loc as Locator Instance
participant DOM as Browser DOM
Test->>Loc: Invoke action (e.g. click)
Loc->>DOM: Locate element
DOM-->>Loc: Element found
Loc->>DOM: Check visibility
DOM-->>Loc: Visible
Loc->>DOM: Check editability / enabled state
DOM-->>Loc: Enabled
Loc->>DOM: Check layout stability
DOM-->>Loc: Stable
Loc->>DOM: Dispatch click event
DOM-->>Test: Complete actionCore Locators API Reference
Playwright recommends using semantic locators. Here is how to configure them in your codebase.
1. Locate by Accessibility Role
The getByRole locator queries elements using their ARIA attributes. This is the primary locator strategy:
import { test, expect } from '@playwright/test';
test('should submit the authentication form', async ({ page }) => {
await page.goto('/login');
// Locate input field by role and placeholder name
await page.getByRole('textbox', { name: 'Email Address' }).fill('user@playwrightpad.info');
// Locate submit button by role and name
await page.getByRole('button', { name: 'Sign In' }).click();
// Verify dashboard message is displayed
await expect(page.getByRole('heading', { name: 'Welcome Back' })).toBeVisible();
});2. Locate by Label Text
Use getByLabel to locate form fields associated with tags:
import { test, expect } from '@playwright/test';
test('should register account values', async ({ page }) => {
await page.goto('/register');
// Locate field using text from label element
await page.getByLabel('Accept Terms of Service').check();
// Verify checkbox is checked
expect(await page.getByLabel('Accept Terms of Service').isChecked()).toBe(true);
});3. Locate by Alt Text and Placeholder
Use getByAltText for images and getByPlaceholder for input placeholder values:
import { test, expect } from '@playwright/test';
test('should verify brand images', async ({ page }) => {
await page.goto('/dashboard');
// Locate profile picture image by alternative text
const avatar = page.getByAltText('User Profile Picture');
await expect(avatar).toBeVisible();
// Locate search box using placeholder text
await page.getByPlaceholder('Search logs...').fill('Errors');
});Handling Nested and Dynamic Elements
When dealing with dashboard lists or tables, you must locate items inside specific parent containers. Use chaining or filtering:
1. Filter by Text or Child Matcher
The filter() method refines locator matching lists based on internal values:
import { test, expect } from '@playwright/test';
test('should select the correct user row', async ({ page }) => {
await page.goto('/admin/users');
// Locate specific table row containing unique email address
const userRow = page.getByRole('row').filter({ hasText: 'admin@playwrightpad.info' });
// Perform action inside the filtered row context
await userRow.getByRole('button', { name: 'Edit' }).click();
});2. Locate Chained Children
Chain selectors to locate nested items inside custom list cards:
import { test, expect } from '@playwright/test';
test('should click specific menu item', async ({ page }) => {
await page.goto('/dashboard');
// Chain parent card to child link
const sidebarLink = page.getByRole('navigation').getByRole('link', { name: 'Settings' });
await sidebarLink.click();
});Locator Method Comparison
The table below contrasts standard locator strategies, outlining use cases and recommendations.
| Locator Strategy | Method Call | Use Case | Recommendation Level |
|---|---|---|---|
| Role Locator | getByRole | Form inputs, buttons, headings | Critical (Primary) |
| Label Locator | getByLabel | Form elements with visible labels | High (Form fields) |
| Text Locator | getByText | Static paragraphs and alerts | Medium (General checks) |
| Test ID | getByTestId | Dynamic tables and dynamic wrappers | High (Dedicated testing IDs) |
| CSS / XPath | locator('css') | Complex external document parsing | Low (Use as fallback only) |
Best Practices for Stable Tests
data-testid="submit-button" in your component files to make them immune to visual re-designs.Here are a few key practices:
click() or fill(), avoiding manual pause commands.Common Mistakes to Avoid
/html/body/div[1]/div[2]/button. These break when developers introduce wrappers.| Bad Pattern | Recommended Alternative |
Chaining raw classes .card > .body > .btn | Semantic role locate getByRole('button', { name: 'Save' }) |
| Manual timeouts before action runs | Let Playwright auto-wait for button readiness |
| Hardcoding database record IDs in selectors | Query text nodes using standard filter conditions |
Frequently Asked Questions
What happens if a locator matches multiple elements?
Playwright throws a strict mode violation error. You must refine the locator configuration using filters or index selectors to target one node.
How do I locate components inside Shadow DOMs?
Playwright's selector engine traverses open Shadow DOM roots automatically. No custom configuration is required.
Can I locate items using regular expressions?
Yes. Functions like getByText and getByRole accept standard regular expression parameters (e.g. /submit/i) for flexible matching.
What is the default locator timeout duration?
The default action timeout is 30 seconds, which is configurable inside the main runner config file.
How do I use data-testid attributes?
Configure your test ID string in the runner options (defaults to data-testid), and locate elements using getByTestId('id').
Should I use XPath in modern projects?
Avoid XPath. CSS selectors or role-based locators are easier to read and maintain across layout shifts.
Does Playwright auto-wait for elements to exist?
Yes. Action methods wait for target elements to exist, become visible, stop animating, and become enabled before execution.
How do I click the first item in a list locator?
Use the first() method or index matcher nth(0) on the resolved locator collection.
Can I create custom locator engines?
Yes. Playwright permits registering custom selector engines using the selectors API.
How do I print the locator matches during debugging?
Use the trace viewer interface or run tests in headed mode with inspector views to highlight matching nodes.
Summary
Resilient locators protect automation test suites from pipeline flakiness. Adopting accessibility role strategies ensures your scripts survive structural modifications.
Related Articles
About The Author
PlaywrightPad Editorial reports on Chromium engines, E2E test optimizations, and AI integration specifications.
Newsletter
Get weekly browser reports sent directly to your inbox.