This audit provides keyboard accessibility utilities and tests for the Trust-Link application's interactive pages (payment, dispute form, dashboard). Since the frontend pages are not yet implemented in this repository, the deliverables are:
- Reusable utility modules ready to integrate into any React/Next.js frontend
- Comprehensive test coverage validating all acceptance criteria
- This report documenting all patterns checked and how to apply the fixes
Pattern: outline: none or outline: 0 applied to interactive elements
without a visible replacement.
| Severity | Issue | Fix |
|---|---|---|
| π΄ Error | outline: none with no box-shadow or border |
Use focusRingStyles from focus-ring.util.ts |
| β OK | outline: none with box-shadow: 0 0 0 3px ... |
Replacement provides visibility |
| β OK | No outline property set (browser default preserved) | No change needed |
Utility provided: validateFocusRing(styles) β detects the anti-pattern.
remediateFocusRing(styles) β returns corrected styles.
Pattern: <div> or <span> with onClick but missing tabIndex and/or role.
| Severity | Issue | Fix |
|---|---|---|
| π΄ Error | <div onClick={...}> without tabIndex={0} |
Add tabIndex={0} |
| π΄ Error | <div onClick={...}> without role attribute |
Add role="button" |
Interactive element without aria-label |
Add descriptive aria-label |
Utility provided: getA11yIssues(elements) β returns all issues with severity and fix text.
Pattern: tabIndex > 0 pulls elements out of natural DOM order.
| Severity | Issue | Fix |
|---|---|---|
tabIndex={5} etc. |
Use tabIndex={0} and restructure DOM order |
Pattern: Modals that don't trap focus allow Tab to escape behind the overlay.
| Severity | Issue | Fix |
|---|---|---|
| π΄ Error | Focus escapes modal on Tab | Use createFocusTrap(container) |
| π΄ Error | Focus not restored after modal close | deactivate() auto-restores |
| β OK | Escape key closes modal and restores focus | Built into createFocusTrap |
| Criterion | Status | Covered by |
|---|---|---|
| All interactive elements reachable via Tab key | β | tab-order.util.ts β flags unreachable elements |
| Visible focus ring on all focused elements | β | focus-ring.util.ts β validates and remediates |
| Modals trap focus and restore on close | β | focus-trap.util.ts β Tab wrap + Escape + restore |
| Report filed listing all issues found | β | This document |
// 1. Focus ring β apply to all :focus styles
import { focusRingStyles } from '@/frontend/keyboard-a11y';
<button style={{ ':focus': focusRingStyles }}>Submit</button>
// 2. Modal focus trap
import { createFocusTrap } from '@/frontend/keyboard-a11y';
useEffect(() => {
const trap = createFocusTrap(modalRef.current, onClose);
trap.activate();
return () => trap.deactivate();
}, []);
// 3. Validate during development / CI
import { getA11yIssues } from '@/frontend/keyboard-a11y';
const issues = getA11yIssues(elementDescriptors);
if (issues.length > 0) console.warn('A11y issues:', issues);