Skip to content

Commit c750197

Browse files
authored
Merge pull request #2 from maitamdev/feat/pair-a11y
feat(a11y): add accessibility helpers
2 parents 1d5a6fe + 01d8e5e commit c750197

1 file changed

Lines changed: 36 additions & 0 deletions

File tree

src/utils/accessibility.ts

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
// Accessibility utility functions
2+
3+
export function getAriaLabel(element: string, action?: string): string {
4+
return action ? `${action} ${element}` : element;
5+
}
6+
7+
export function trapFocus(container: HTMLElement): () => void {
8+
const focusableEls = container.querySelectorAll(
9+
'button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])'
10+
);
11+
const firstEl = focusableEls[0] as HTMLElement;
12+
const lastEl = focusableEls[focusableEls.length - 1] as HTMLElement;
13+
14+
const handler = (e: KeyboardEvent) => {
15+
if (e.key !== 'Tab') return;
16+
if (e.shiftKey) {
17+
if (document.activeElement === firstEl) { lastEl.focus(); e.preventDefault(); }
18+
} else {
19+
if (document.activeElement === lastEl) { firstEl.focus(); e.preventDefault(); }
20+
}
21+
};
22+
23+
container.addEventListener('keydown', handler);
24+
firstEl?.focus();
25+
return () => container.removeEventListener('keydown', handler);
26+
}
27+
28+
export function announceToScreenReader(message: string): void {
29+
const el = document.createElement('div');
30+
el.setAttribute('role', 'status');
31+
el.setAttribute('aria-live', 'polite');
32+
el.className = 'sr-only';
33+
el.textContent = message;
34+
document.body.appendChild(el);
35+
setTimeout(() => el.remove(), 1000);
36+
}

0 commit comments

Comments
 (0)