Skip to content

Add focus trapping and dialog accessibility to the custom modal/overlay components #1138

Description

@RUKAYAT-CODER

Background
src/components/ui/Modal.tsx documents itself as having a focus trap, but it only locks body scroll and closes on Escape -- it never traps Tab focus inside the dialog and never restores focus to the trigger element on close. Several overlays bypass Modal entirely and reimplement dialog markup with the same gaps: src/components/CommandPalette.tsx, src/components/ConflictResolver.tsx, src/components/editor/MediaEmbedder.tsx, src/components/courses/VideoPreview.tsx, src/components/notificationcenter.tsx (its role=dialog dropdown panel), and src/components/CookieConsentBanner.tsx. As a result keyboard and screen-reader users can Tab out of an open dialog into the page behind it, and focus is lost when the dialog closes.

Implementation Plan

  • Add a shared hook src/hooks/useFocusTrap.ts that traps Tab / Shift+Tab within the active dialog, restores focus to the opener on unmount, and supports an optional initial-focus target.
  • Implement a real focus trap plus focus restore in src/components/ui/Modal.tsx and correct its docstring.
  • Apply the hook, plus consistent aria-modal / aria-labelledby wiring and Escape handling, to CommandPalette.tsx, ConflictResolver.tsx, MediaEmbedder.tsx, VideoPreview.tsx, notificationcenter.tsx, and CookieConsentBanner.tsx.
  • Add benchmarks/metrics where meaningful (e.g. automated axe/a11y checks before/after).
  • Add regression tests (keyboard-navigation and focus-trap tests).
  • Document the change.

Files in Scope (8)
src/hooks/useFocusTrap.ts (new), src/components/ui/Modal.tsx, src/components/CommandPalette.tsx, src/components/ConflictResolver.tsx, src/components/editor/MediaEmbedder.tsx, src/components/courses/VideoPreview.tsx, src/components/notificationcenter.tsx, src/components/CookieConsentBanner.tsx

Acceptance Criteria

  • Measurable accessibility improvement demonstrated with before/after checks
  • No regression in existing functionality
  • Tests pass and code follows project standards
  • Change is documented

Difficulty
Medium

Metadata

Metadata

Assignees

Labels

GrantFox OSSIssue tracked in GrantFox OSSMaybe RewardedIssue may be eligible for a GrantFox rewardThird CampaignCampaign: Third CampaignenhancementNew feature or requestfrontendNexjs

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions