# Locator Selection Standards
## Rule
All Playwright tests MUST use semantic locators as the primary selector strategy. CSS selectors and XPath are prohibited unless no semantic alternative exists.
## Locator Priority (Mandatory Order)
1. `getByRole()` — buttons, links, headings, textboxes, checkboxes
2. `getByLabel()` — form inputs with associated labels
3. `getByPlaceholder()` — inputs with placeholder text
4. `getByText()` — elements identified by visible text content
5. `getByAltText()` — images with alt attributes
6. `getByTestId()` — last resort for elements without semantic meaning
## Examples
### Good
```typescript
page.getByRole('button', { name: 'Submit' });
page.getByRole('link', { name: 'Sign up' });
page.getByLabel('Email address');
page.getByRole('heading', { name: 'Dashboard', level: 1 });
page.getByRole('navigation').getByRole('link', { name: 'Home' });
```
### Bad
```typescript
page.locator('.btn-primary');
page.locator('#submit-btn');
page.locator('div.card > button');
page.locator('[data-cy="submit"]');
page.locator('//button[@type="submit"]');
```
## Exceptions
- Canvas elements, charts, and SVG containers may use `getByTestId()`
- Third-party widget iframes may require `frameLocator()` with CSS
- Document each exception with a comment explaining why semantic locators are not possible
## Enforcement
Add to ESLint config with `eslint-plugin-playwright`:
```json
{
"rules": {
"playwright/prefer-native-locators": "error",
"playwright/no-raw-locators": "warn"
}
}
```