SoftwareTestPilot
Automation TestingPublished: 12 min read

Playwright Locators — 20 Real Examples (2026 Guide)

Every Playwright locator strategy explained with 20 real examples: getByRole, getByLabel, chaining, filtering, and the locator patterns senior SDETs prefer over XPath.

Avinash K
Founder & QA Engineer at SoftwareTestPilot
Share:XLinkedInWhatsApp
Playwright locators cheat sheet — 20 real examples across roles, labels, chains.
Playwright locators cheat sheet — 20 real examples across roles, labels, chains.

Last updated 2026-07-20 · 12 min read · By Avinash K

Locators are where 80% of Playwright test debt lives. Get them right and the suite stays green through 6 months of UI refactors; get them wrong and every sprint costs a day of maintenance. This is the locator playbook we use across 5,000+ tests in production.

Key takeaways

  • The 5 built-in locator strategies ranked by resilience.
  • 20 worked examples across forms, tables, modals, and iframes.
  • When to use filter() vs nth() vs chaining.
  • Why getByRole beats XPath in 95% of cases.

1. The priority order Playwright recommends

  1. page.getByRole() — accessibility-first, resilient to DOM changes.
  2. page.getByLabel() — for form fields.
  3. page.getByPlaceholder() — when no label exists.
  4. page.getByText() — for buttons and links with unique copy.
  5. page.getByTestId() — last resort, when semantic queries fail.

Only fall back to CSS or XPath for third-party widgets you cannot instrument. See the official locators reference.

2. Ten basic examples

// 1. Button by role + name
await page.getByRole('button', { name: 'Sign in' }).click();

// 2. Form field by label
await page.getByLabel('Email').fill('a@b.com');

// 3. Link
await page.getByRole('link', { name: 'Pricing' }).click();

// 4. Checkbox
await page.getByRole('checkbox', { name: 'I agree' }).check();

// 5. Select option
await page.getByLabel('Country').selectOption('India');

// 6. Radio
await page.getByRole('radio', { name: 'Monthly' }).check();

// 7. Text (exact)
await page.getByText('Welcome back', { exact: true }).waitFor();

// 8. Placeholder
await page.getByPlaceholder('Search products').fill('shoes');

// 9. Alt text (image)
await page.getByAltText('Company logo').click();

// 10. Test id
await page.getByTestId('cart-count').should('have.text', '3');

3. Ten advanced examples — filter, chain, iframe

// 11. Filter a list by text
await page.getByRole('listitem').filter({ hasText: 'Product A' }).click();

// 12. Chain within a card
await page.getByRole('article', { name: 'Order 4211' })
  .getByRole('button', { name: 'Cancel' }).click();

// 13. Nth (avoid if possible)
await page.getByRole('row').nth(2).click();

// 14. Combine has and hasNot
await page.getByRole('row').filter({ hasNot: page.getByText('Delivered') });

// 15. Iframe
await page.frameLocator('#stripe').getByLabel('Card number').fill('4242 ...');

// 16. Shadow DOM (built-in support)
await page.getByRole('button', { name: 'Open' }).click();

// 17. Regex text
await page.getByText(/order #\d+/i).click();

// 18. Wait for locator
await page.getByText('Loaded').waitFor({ state: 'visible' });

// 19. Assert count
await expect(page.getByRole('row')).toHaveCount(10);

// 20. Screenshot a single element
await page.getByRole('article', { name: 'Order 4211' }).screenshot({ path: 'card.png' });

4. Anti-patterns to avoid

  • page.locator('xpath=//div[3]/span[2]') — positional XPath dies on any refactor.
  • CSS with generated class names (.css-abc123) — Tailwind and CSS-in-JS make these unstable.
  • Chaining .nth(0) instead of .first() — less readable.
  • Missing await before an action — silent race condition.

Compare against Selenium's locator model to see why Playwright's role-based approach is more maintainable.

Frequently asked questions

1.Should I still use CSS selectors in Playwright?
Only for third-party widgets you can't instrument with test ids. Prefer role/label/text for anything you own.
2.Is getByTestId better than getByRole?
No — getByRole tests real user paths. getByTestId is the escape hatch when semantics are ambiguous.
3.How do I locate shadow DOM elements?
Playwright pierces open shadow roots automatically. For closed shadow DOM, use a test id inside the component.
4.Can I use XPath for iframe elements?
Use frameLocator() then role-based selectors inside. XPath into iframes is fragile and hard to debug.