38 / 74 · 10 Visual & Accessibility Testing · Keyboard Navigation Testing← prev⊞ allnext →☰ Read as one page
7.6Keyboard Interaction Patterns
Different component types have expected keyboard behaviors defined by WAI-ARIA:
| Component | Tab | Enter/Space | Arrow Keys | Escape |
|---|---|---|---|---|
| Button | Focus | Activate | N/A | N/A |
| Link | Focus | Navigate | N/A | N/A |
| Checkbox | Focus | Toggle | N/A | N/A |
| Radio group | Focus group | Select | Move selection | N/A |
| Dropdown/Select | Focus | Open | Navigate options | Close |
| Tab panel | Focus active tab | N/A | Switch tabs | N/A |
| Modal dialog | Focus first element | N/A | N/A | Close modal |
| Menu | Focus first item | Activate | Navigate items | Close menu |
| Accordion | Focus header | Toggle section | N/A | N/A |
test('dropdown keyboard interactions follow WAI-ARIA patterns', async ({ page }) => {
await page.goto('/form');
// Tab to the dropdown
const dropdown = page.locator('[role="listbox"]');
await dropdown.focus();
// Space opens the dropdown
await page.keyboard.press('Space');
await expect(page.locator('[role="option"]').first()).toBeVisible();
// Arrow down navigates options
await page.keyboard.press('ArrowDown');
const focused = await page.evaluate(() =>
document.activeElement?.getAttribute('aria-selected')
);
expect(focused).toBe('true');
// Enter selects the option
await page.keyboard.press('Enter');
await expect(page.locator('[role="option"]').first()).not.toBeVisible();
// Escape closes without selecting
await page.keyboard.press('Space'); // Reopen
await page.keyboard.press('Escape');
await expect(page.locator('[role="option"]').first()).not.toBeVisible();
});
Keyboard navigation testing catches real user pain. If your most critical flows are not completable via keyboard, you are both excluding users and inviting legal action. Test every critical user journey with keyboard-only interaction.