Skip to content

feat(a11y): add focus trap to Modal and manage focus on route changes (#229)#236

Merged
RUKAYAT-CODER merged 1 commit into
rinafcode:mainfrom
solomonokeke012-bot:feat/229-focus-management
Apr 27, 2026
Merged

feat(a11y): add focus trap to Modal and manage focus on route changes (#229)#236
RUKAYAT-CODER merged 1 commit into
rinafcode:mainfrom
solomonokeke012-bot:feat/229-focus-management

Conversation

@solomonokeke012-bot
Copy link
Copy Markdown
Contributor

Summary

Closes #229

Implements proper focus management per the accessibility issue spec.

Changes

  • src/components/ui/Modal.tsx (new) — Reusable accessible modal with:

    • Focus trap via existing useFocusTrap hook (focus returns to trigger on close)
    • role="dialog", aria-modal, aria-labelledby with stable useId()
    • Escape key and backdrop-click to close
    • Body scroll lock while open
    • Screen reader announcement on open
  • src/hooks/useAccessibility.tsx — Added useFocusOnRouteChange(pathname) hook that moves focus to the <main> landmark on every route change

  • src/components/accessibility/RouteChangeAnnouncer.tsx (new) — Thin client component that reads usePathname() and calls useFocusOnRouteChange; renders nothing

  • src/providers/RootProviders.tsx — Mounts <RouteChangeAnnouncer /> inside <AccessibilityProvider> for app-wide route focus management

  • src/components/index.ts — Exports Modal from the component barrel

Testing

  • Open a modal → focus moves inside; Tab cycles within; Escape/backdrop closes and focus returns to trigger
  • Navigate between routes → focus moves to <main> content area

Acceptance Criteria

  • Focus trap in modals
  • Focus returned to trigger on close
  • Focus managed on route changes

Closes rinafcode#229

- Add src/components/ui/Modal.tsx: accessible dialog with focus trap,
  Escape-to-close, aria-labelledby, body scroll lock, and SR announcement
- Add useFocusOnRouteChange hook to useAccessibility.tsx: moves focus to
  <main> landmark on every pathname change
- Add RouteChangeAnnouncer component (renders nothing, side-effect only)
- Wire RouteChangeAnnouncer into RootProviders inside AccessibilityProvider
- Export Modal from src/components/index.ts barrel
@drips-wave
Copy link
Copy Markdown

drips-wave Bot commented Apr 27, 2026

@solomonokeke012-bot Great news! 🎉 Based on an automated assessment of this PR, the linked Wave issue(s) no longer count against your application limits.

You can now already apply to more issues while waiting for a review of this PR. Keep up the great work! 🚀

Learn more about application limits

@RUKAYAT-CODER RUKAYAT-CODER merged commit 50d359b into rinafcode:main Apr 27, 2026
1 of 4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Accessibility - Focus Management

2 participants