Skip to content

fix: make the exit confirmation an accessible dialog#974

Merged
Somil450 merged 1 commit into
Somil450:mainfrom
Anexus5919:fix/accessible-exit-modal
Jul 9, 2026
Merged

fix: make the exit confirmation an accessible dialog#974
Somil450 merged 1 commit into
Somil450:mainfrom
Anexus5919:fix/accessible-exit-modal

Conversation

@Anexus5919

Copy link
Copy Markdown
Contributor

📌 Related Issue

Fixes #891


📝 Description

The "Confirm Exit" modal, duplicated in App.tsx and WorkoutScreen.tsx, was built from plain <div>s: no dialog role, no focus management or trap, no Escape to close, and (in App) a "Stay" button with no styling that rendered low-contrast.

🔹 What has been changed?

  • New reusable ExitConfirmModal with role="dialog", aria-modal="true", and aria-labelledby (id from useId); focus moved to the non-destructive Stay button on open; Tab focus trapped within the dialog (wraps both ends); Escape closes (invokes Stay); focus restored to the previously focused element on close; and the app's btn-outline (Stay) / btn-neon + red (Exit) classes for adequate, theme-aware contrast.
  • Replaced the inline modal in both App.tsx and WorkoutScreen.tsx with <ExitConfirmModal> (preserving each one's message and exit action).

🔹 Why are these changes needed?

  • A confirm dialog should be announced as a dialog, trap focus, close on Escape, and restore focus, none of which the plain-div version did. Extracting one accessible component fixes both copies and gives the "Stay" button proper contrast.

🛠️ Type of Change

  • 🐛 Bug Fix
  • 🎨 UI/UX Improvement

🧪 Testing

✅ Tests Performed

  • Tested locally
  • npx tsc --noEmit clean; npx eslint clean for the change (the pre-existing user?.uid exhaustive-deps warning on an unrelated WorkoutScreen effect is unchanged).
  • Traced the controlled focus flow (open -> focus Stay, Tab traps, Escape -> Stay, close -> restore focus).

🔹 Note on automated tests

No committed test: the focus-trap/Escape behavior needs @testing-library/react, which can't currently run (@testing-library/dom evicted from node_modules).

🌐 Browsers Tested

Not applicable here (focus/dialog behavior; verified via reasoning and the Accessibility pane).


📷 Screenshots / Demo (if applicable)

A capture comparing the Stay/Exit button contrast and showing Tab staying within the modal would help.


📋 Checklist

  • I have read the project's CONTRIBUTING guidelines
  • My code follows the project style guidelines
  • I have performed a self-review of my code
  • I have tested my changes locally
  • I have added/updated documentation where necessary (not applicable)
  • My changes do not introduce new warnings or errors
  • This PR is linked to an existing issue

💬 Additional Notes

Branched from upstream/main; merges cleanly with the current base. Fixes both duplicated copies of the modal (App and WorkoutScreen) via one shared component.

@vercel

vercel Bot commented Jun 26, 2026

Copy link
Copy Markdown

@Anexus5919 is attempting to deploy a commit to the somiljain2024-4175's projects Team on Vercel.

A member of the Team first needs to authorize it.

@Anexus5919

Copy link
Copy Markdown
Contributor Author

@Somil450 @diksha78dev Kindly have a review on this pr. Thanks!

The exit-confirm modal (duplicated in App and WorkoutScreen) was plain
divs: no dialog role, no focus management or trap, no Escape to close, and
App's "Stay" button had no styling so it rendered with low contrast.

Extract a reusable ExitConfirmModal with role="dialog", aria-modal, and
aria-labelledby; move focus to the safe "Stay" action on open, trap Tab
within the dialog, close on Escape, and restore focus to the trigger on
close. Use the app's btn-outline/btn-neon classes so both buttons have
adequate contrast. Render it from both App and WorkoutScreen.
@Anexus5919 Anexus5919 force-pushed the fix/accessible-exit-modal branch from 26d6cfb to de859e5 Compare July 1, 2026 07:21
@Anexus5919

Copy link
Copy Markdown
Contributor Author

@Somil450 @diksha78dev Kindly have a review on this pr. Thanks!

@Anexus5919

Copy link
Copy Markdown
Contributor Author

This failing check is from main, not this PR. Main's CI is currently broken (ShieldAlert used without importing it, plus untyped "privacy"/"terms&conditions" screens), so every PR goes red, even docs-only ones. Fix is up in #1039. Once it merges, a rebase turns this green. Merges cleanly with base.

@Somil450 Somil450 self-requested a review July 9, 2026 14:02
@Somil450 Somil450 added gssoc-26 Marks GSSoC issues gssoc:approved Officially reviewed and approved GSSoC contribution ready for scoring mentor:Somil450 Reviewed and mentored by Somil450 for GSSoC contribution tracking. level:intermediate Moderate complexity requiring good understanding of project structure and implementation. type:bug mentor-approved labels Jul 9, 2026
@Somil450 Somil450 merged commit bef67bd into Somil450:main Jul 9, 2026
0 of 12 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

gssoc:approved Officially reviewed and approved GSSoC contribution ready for scoring gssoc-26 Marks GSSoC issues level:intermediate Moderate complexity requiring good understanding of project structure and implementation. mentor:Somil450 Reviewed and mentored by Somil450 for GSSoC contribution tracking. mentor-approved type:bug

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Exit confirmation modal is not an accessible dialog (no role/focus-trap/Escape; low-contrast Stay)

2 participants