Implementation:Microsoft Playwright Locator API
| Knowledge Sources | |
|---|---|
| Domains | Testing, Browser_Automation |
| Last Updated | 2026-02-11 00:00 GMT |
Overview
Concrete tool for locating DOM elements using resilient selectors and performing user-like interactions, provided by the Playwright library.
Description
The Locator API is Playwright's primary mechanism for finding and interacting with elements on a web page. Locators are created through page.locator() or the various page.getBy*() methods, and they represent a way to find elements at any moment -- they are resolved lazily, meaning the actual DOM query runs at interaction time, not at creation time.
The Locator class is implemented in packages/playwright-core/src/client/locator.ts and provides a comprehensive set of interaction methods (click, fill, check, press, hover, selectOption, tap) and composition methods (filter, first, nth, last, and, or). All getBy* methods on Page and Frame delegate through Frame.locator(), constructing selector strings that use Playwright's built-in selector engines (role, text, label, placeholder, alt, title, testid).
Every interaction method enforces actionability checks before performing the action. These checks include verifying the element is visible, stable, enabled, and able to receive events. The checks auto-retry until a configurable timeout is reached.
Usage
Use the Locator API whenever you need to find or interact with elements in a test. Prefer page.getByRole(), page.getByText(), and page.getByLabel() over page.locator() with CSS selectors. Use chaining methods like filter() and first/nth() to narrow results. Locators are the recommended replacement for the older page.$() and page.$$() APIs.
Code Reference
Source Location
- Repository: playwright
- File (Page methods):
packages/playwright-core/src/client/page.ts(lines 668-698) - File (Locator class):
packages/playwright-core/src/client/locator.ts(lines 40-474)
Signature
// Creating locators
page.locator(selector: string, options?: LocatorOptions): Locator;
page.getByRole(role: AriaRole, options?: ByRoleOptions): Locator;
page.getByText(text: string | RegExp, options?: { exact?: boolean }): Locator;
page.getByLabel(text: string | RegExp, options?: { exact?: boolean }): Locator;
page.getByPlaceholder(text: string | RegExp, options?: { exact?: boolean }): Locator;
page.getByAltText(text: string | RegExp, options?: { exact?: boolean }): Locator;
page.getByTitle(text: string | RegExp, options?: { exact?: boolean }): Locator;
page.getByTestId(testId: string | RegExp): Locator;
// Locator interaction methods
Locator.click(options?: ClickOptions): Promise<void>; // L108
Locator.fill(value: string, options?: FillOptions): Promise<void>; // L143
Locator.check(options?: CheckOptions): Promise<void>; // L104
Locator.press(key: string, options?: PressOptions): Promise<void>; // L309
Locator.hover(options?: HoverOptions): Promise<void>; // L269
Locator.selectOption(values: SelectOption, options?: SelectOptionOptions): Promise<string[]>; // L327
Locator.tap(options?: TapOptions): Promise<void>; // L346
// Locator composition methods
Locator.filter(options?: FilterOptions): Locator; // L200
Locator.first: Locator; // L224
Locator.nth(index: number): Locator; // L232
Locator.and(locator: Locator): Locator; // L236
Locator.or(locator: Locator): Locator; // L242
Import
// Locators are accessed via the page object - no separate import needed.
// The page fixture is automatically provided in Playwright tests:
import { test, expect } from '@playwright/test';
test('example', async ({ page }) => {
const locator = page.locator('.my-class');
const button = page.getByRole('button', { name: 'Submit' });
});
I/O Contract
Inputs
| Name | Type | Required | Description |
|---|---|---|---|
| selector | string |
Yes (for page.locator()) |
CSS selector, XPath, or Playwright selector engine expression (e.g., role=button[name="Submit"]).
|
| role | AriaRole |
Yes (for getByRole) |
ARIA role such as 'button', 'link', 'heading', 'textbox', 'checkbox', etc.
|
| LocatorOptions.hasText | RegExp | No | Filters to elements containing the given text. |
| LocatorOptions.hasNotText | RegExp | No | Filters out elements containing the given text. |
| LocatorOptions.has | Locator |
No | Filters to elements that contain a descendant matching the given locator. |
| LocatorOptions.hasNot | Locator |
No | Filters out elements that contain a descendant matching the given locator. |
| LocatorOptions.visible | boolean |
No | When set, filters to elements that are visible or not visible. |
| ByRoleOptions.name | RegExp | No | Accessible name of the element. |
| ByRoleOptions.checked | boolean |
No | Filter by checked state. |
| ByRoleOptions.disabled | boolean |
No | Filter by disabled state. |
| ByRoleOptions.exact | boolean |
No | Whether the name match should be exact (default: false, uses substring). |
| ByRoleOptions.expanded | boolean |
No | Filter by expanded state. |
| ByRoleOptions.level | number |
No | Filter headings by level (1-6). |
| ByRoleOptions.pressed | boolean |
No | Filter by pressed state. |
| ByRoleOptions.selected | boolean |
No | Filter by selected state. |
| ByRoleOptions.includeHidden | boolean |
No | Include hidden elements in the results (default: false). |
Outputs
| Name | Type | Description |
|---|---|---|
| Locator | Locator |
A locator instance representing the query. Locators are lazy -- the DOM query is not executed until an interaction or assertion method is called. |
| click/fill/check/etc. | Promise<void> |
Interaction methods return a Promise that resolves when the action completes (after auto-waiting for actionability). |
| selectOption | Promise<string[]> |
Returns the array of selected option values after the selection is made. |
Usage Examples
Basic Example
import { test, expect } from '@playwright/test';
test('interact with a form', async ({ page }) => {
await page.goto('https://example.com/login');
// Locate by role and accessible name
await page.getByRole('textbox', { name: 'Email' }).fill('user@example.com');
await page.getByRole('textbox', { name: 'Password' }).fill('secret');
await page.getByRole('button', { name: 'Sign in' }).click();
// Verify navigation after login
await expect(page.getByRole('heading', { name: 'Dashboard' })).toBeVisible();
});
Chaining and Filtering Example
import { test, expect } from '@playwright/test';
test('filter and chain locators', async ({ page }) => {
await page.goto('https://example.com/products');
// Filter a list to find a specific product row
const productRow = page
.getByRole('listitem')
.filter({ hasText: 'Wireless Mouse' });
// Interact with a button within that specific row
await productRow.getByRole('button', { name: 'Add to cart' }).click();
// Use .and() to combine locators
const enabledSubmit = page
.getByRole('button', { name: 'Checkout' })
.and(page.locator(':not([disabled])'));
await expect(enabledSubmit).toBeVisible();
// Use .first and .nth for indexed access
const firstItem = page.getByRole('listitem').first();
const thirdItem = page.getByRole('listitem').nth(2);
await expect(firstItem).toBeVisible();
await expect(thirdItem).toBeVisible();
});
Various getBy Methods Example
import { test } from '@playwright/test';
test('use different locator strategies', async ({ page }) => {
await page.goto('https://example.com/form');
// By label text (associated <label> element)
await page.getByLabel('Username').fill('john_doe');
// By placeholder text
await page.getByPlaceholder('Enter your email').fill('john@example.com');
// By visible text content
await page.getByText('Terms and Conditions').click();
// By alt text (images)
await page.getByAltText('Company Logo').click();
// By title attribute
await page.getByTitle('Close dialog').click();
// By test ID (data-testid attribute)
await page.getByTestId('submit-button').click();
});