32 / 74 · 10 Visual & Accessibility Testing · ARIA Labels and Color Contrast← prev⊞ allnext →☰ Read as one page
6.4Common ARIA Mistakes
| Mistake | Why It Is Wrong | Correct Approach |
|---|---|---|
<div role="button"> |
Missing keyboard handling | Use <button> |
aria-label on <div> without role |
aria-label has no effect on generic elements | Add a role or use a semantic element |
aria-hidden="true" on focusable element |
Removes from accessibility tree but still focusable | Also add tabindex="-1" |
Duplicate aria-labelledby targets |
Confusing screen reader output | Each label target should be unique |
role="presentation" on interactive element |
Removes semantics from clickable element | Never suppress semantics on interactive elements |
| Using ARIA to fix a broken HTML structure | ARIA compensates but does not truly fix issues | Fix the HTML structure first |
Testing for these mistakes can be automated:
test('no ARIA anti-patterns', async ({ page }) => {
await page.goto('/');
const antiPatterns = await page.evaluate(() => {
const issues: string[] = [];
// Check for divs with role="button" (should be <button>)
document.querySelectorAll('[role="button"]:not(button)').forEach(el => {
issues.push(`Non-button element with role="button": ${el.outerHTML.substring(0, 100)}`);
});
// Check for aria-hidden on focusable elements
document.querySelectorAll('[aria-hidden="true"]').forEach(el => {
const tabindex = el.getAttribute('tabindex');
if (tabindex !== '-1' && (el as HTMLElement).tabIndex >= 0) {
issues.push(`Focusable element with aria-hidden: ${el.outerHTML.substring(0, 100)}`);
}
});
return issues;
});
expect(antiPatterns).toEqual([]);
});
ARIA and color contrast testing form the backbone of automated accessibility checks. They are fast to run, catch real issues, and require minimal setup. Every project should have these tests from day one.