A hands-on reference for every recommended Playwright locator. Each method includes multiple real-world examples with the exact HTML you can target from your tests.
page.getByRole()Locate elements by their ARIA role and accessible name — the most resilient and strongly recommended locator.
await page.getByRole('button', { name: 'Submit order' }).click();
await page.getByRole('link', { name: 'Documentation', exact: true }).click();
await expect(page.getByRole('heading', { level: 3, name: 'Account settings' })).toBeVisible();
await page.getByRole('textbox', { name: 'Full name' }).fill('Ada Lovelace');
await page.getByRole('searchbox', { name: 'Search site' }).fill('locators');
await page.getByRole('checkbox', { name: 'Subscribe', checked: false }).check();
await page.getByRole('radio', { name: 'Express shipping' }).check();
await expect(page.getByRole('meter', { name: 'Disk usage' })).toHaveAttribute('value', '6');
await page.getByRole('combobox', { name: 'Country' }).selectOption('India');
await page.getByRole('spinbutton', { name: 'Quantity' }).fill('3');
await page.getByRole('slider', { name: 'Volume' }).fill('70');
await page.getByRole('row', { name: 'Ada Lovelace Admin' })
.getByRole('cell', { name: 'Admin' }).click();
| Name | Role |
|---|---|
| Ada Lovelace | Admin |
| Alan Turing | Editor |
await expect(page.getByRole('listitem')).toHaveCount(3);
await expect(page.getByRole('progressbar', { name: 'Upload' })).toHaveAttribute('value', '65');
await page.getByRole('button', { name: 'Shipping details' }).click();
Ships in 2–3 business days via standard courier.
const dialog = page.getByRole('dialog', { name: 'Delete item' });
await dialog.getByRole('button', { name: 'Confirm' }).click();
await expect(page.getByRole('img', { name: 'Team photo' })).toBeVisible();
page.getByText()Find elements by their text content — substring, exact, or regular expression.
await expect(page.getByText('Welcome back')).toBeVisible();
Welcome back, Sagar! You have 3 new messages.
await page.getByText('Delete', { exact: true }).click();
await expect(page.getByText(/\$\d+\.\d{2}/)).toHaveText('$49.99');
await page.getByRole('listitem')
.filter({ hasText: 'Premium' })
.getByRole('button').click();
page.getByLabel()Target form controls by their associated <label> or aria-label — the best way to fill forms.
forawait page.getByLabel('Email address').fill('user@example.com');
await page.getByLabel('Remember me').check();
aria-labelawait page.getByLabel('Card number').fill('4242 4242 4242 4242');
await page.getByLabel('Password', { exact: true }).fill('S3cr3t!');
page.getByPlaceholder()Locate inputs and textareas that expose a placeholder attribute.
await page.getByPlaceholder('Search the docs').fill('locators');
await page.getByPlaceholder('Leave a comment…').fill('Great work!');
await page.getByPlaceholder('name@work-email.com', { exact: true }).fill('a@b.com');
page.getByAltText()Find images (and other elements with alt) by their alternative text.
await expect(page.getByAltText('Mountain landscape')).toBeVisible();
await page.getByAltText('Product thumbnail').click();
await expect(page.getByAltText(/avatar/i)).toHaveCount(1);
page.getByTitle()Locate elements by their title attribute (shown as a native tooltip on hover).
await page.getByTitle('Close dialog').click();
await expect(page.getByTitle('Verified account')).toBeVisible();
await page.getByTitle('Open settings', { exact: true }).click();
page.getByTestId()Locate elements by their data-testid — stable IDs that never change with copy or styling.
await page.getByTestId('checkout-button').click();
await page.getByTestId('product-card')
.getByRole('button', { name: 'Add' }).click();
// playwright.config.ts
export default defineConfig({
use: { testIdAttribute: 'data-qa' },
});
// test
await page.getByTestId('login-form').isVisible();
The definitive cheat-sheet: each HTML element, its correct implicit ARIA role, and how to reach it with getByRole().
| HTML element | Implicit ARIA role | getByRole() usage & notes |
|---|---|---|
| Landmarks & sectioning | ||
<header> |
banner |
Top-level page header. getByRole('banner'). |
<nav> |
navigation |
getByRole('navigation', { name: 'Primary' }). |
<main> |
main |
One per page. getByRole('main'). |
<aside> |
complementary |
getByRole('complementary'). |
<footer> |
contentinfo |
Top-level footer. getByRole('contentinfo'). |
<section> |
region* |
Only when it has an accessible name (aria-label). getByRole('region', { name }). |
<article> |
article |
getByRole('article'). |
<form> |
form* |
Role form only when named. getByRole('form', { name }). |
| Headings & text content | ||
<h1>–<h6> |
heading |
getByRole('heading', { level: 1, name }). |
<p> |
paragraph |
Usually targeted with getByText() instead. |
<blockquote> |
blockquote |
getByRole('blockquote'). |
<ul>, <ol> |
list |
getByRole('list'). |
<li> |
listitem |
getByRole('listitem'). |
<dl> / <dt> / <dd> |
term / definition |
<dl> itself has no role; <dt>→term, <dd>→definition. |
<a href> |
link |
getByRole('link', { name }). An <a> with no href has no role. |
<strong> |
strong |
Rarely queried by role. |
<em> |
emphasis |
Rarely queried by role. |
<code> |
code |
getByRole('code'). |
<img alt> |
img |
getByRole('img', { name }) or getByAltText(). Empty alt="" → presentation. |
<figure> |
figure |
getByRole('figure'). |
<hr> |
separator |
getByRole('separator'). |
| Forms & interactive controls | ||
<button> |
button |
getByRole('button', { name }). |
<input type="text"> |
textbox |
Also email, tel, url map here — except password. |
<input type="search"> |
searchbox |
getByRole('searchbox', { name }). |
<input type="password"> |
no role | Not exposed as textbox. Use getByLabel('Password'). |
<input type="number"> |
spinbutton |
getByRole('spinbutton', { name }). |
<input type="checkbox"> |
checkbox |
getByRole('checkbox', { name, checked }). |
<input type="radio"> |
radio |
getByRole('radio', { name }). |
<input type="range"> |
slider |
getByRole('slider', { name }). |
<input type="file"> |
no role | Use setInputFiles() via getByLabel(). |
<textarea> |
textbox |
getByRole('textbox', { name }). |
<select> |
combobox |
listbox when multiple or size>1. getByRole('combobox', { name }). |
<option> |
option |
getByRole('option', { name }). |
<optgroup> |
group |
getByRole('group'). |
<fieldset> |
group |
Named by its <legend>. |
<label>, <legend> |
no role | Provide accessible names for other controls. |
<output> |
status |
Live region. getByRole('status'). |
<progress> |
progressbar |
getByRole('progressbar', { name }). |
<meter> |
meter |
getByRole('meter', { name }). |
| Tables | ||
<table> |
table |
grid when interactive. getByRole('table'). |
<caption> |
caption |
Names the table. |
<thead>, <tbody>, <tfoot> |
rowgroup |
getByRole('rowgroup'). |
<tr> |
row |
getByRole('row', { name }). |
<th scope="col"> |
columnheader |
getByRole('columnheader', { name }). |
<th scope="row"> |
rowheader |
getByRole('rowheader', { name }). |
<td> |
cell |
gridcell inside a grid. getByRole('cell'). |
| Disclosure & dialog | ||
<details> |
group |
Expandable container. |
<summary> |
button |
getByRole('button', { name, expanded }). |
<dialog> |
dialog |
getByRole('dialog', { name }). |
ARIA-only roles (no native element — set with role="…") |
||
role="tablist / tab / tabpanel" |
tab, tablist, tabpanel |
getByRole('tab', { name, selected }). |
role="switch" |
switch |
getByRole('switch', { name, checked }). |
role="menu / menubar / menuitem" |
menu, menuitem |
getByRole('menuitem', { name }). |
role="alert / status / log" |
alert, status, log |
Live regions. getByRole('alert'). |
role="tooltip" |
tooltip |
getByRole('tooltip'). |
role="tree / treeitem" |
tree, treeitem |
getByRole('treeitem', { name, expanded }). |
role="grid / gridcell" |
grid, gridcell |
Interactive data grids. |
*Conditional role — applies only when the element is named or configured as noted. Common getByRole() options: name, exact, checked,
pressed, selected, expanded, level, disabled.