Skip to content

fix(web): announce the Safe-mode confirm and Saved Credentials as dialogs; Escape closes Saved Credentials - #582

Merged
huyplb merged 2 commits into
mainfrom
fix/dialog-a11y
Nov 1, 2026
Merged

huyplb merged 2 commits into
mainfrom
fix/dialog-a11y

Conversation

@huyplb

@huyplb huyplb commented Nov 1, 2026 •

Copy link
Copy Markdown
Contributor

From the 2026-11-01 manual walk.

Safe-mode confirm (WriteConfirmDialog, sql-write-confirm): a plain div.modal-overlay, so a screen reader wasn't told a dialog had opened. It now has role="dialog", aria-modal="true", and aria-labelledby pointing at its title, e.g. Safe mode: run UPDATE statements?

Saved Credentials (CredentialManager):

  • the same dialog semantics, named Saved Credentials
  • Escape closes it, like the other dialogs. It doesn't while the credential form is open on top, so Escape closes only the top layer.
  • the icon-only close button (cred-close-btn) is now named Close saved credentials and has type="button"

useEscapeKey (shared/lib/useEscapeKey.ts) is the Escape listener that WorkspaceSettingsDialog and others each write by hand: a ref for the callback, registered once, skipping keys another handler already claimed. It adds an enabled flag for layered dialogs. I haven't moved the existing hand-written listeners over, to keep this PR small.

Tests:

  • WriteConfirmDialog.test.tsx: role and name
  • CredentialManager.test.tsx: role, name and close-button name; Escape closes; Escape with the form open doesn't

A/B: without the fix, 3 of the 4 fail. With Escape unguarded, the form-on-top test fails. With the fix, all pass.

Live check: I opened Saved Credentials in the app and confirmed the dialog role, name and button label, and that a real Escape closes it. tsc, eslint and the naming test are clean.

🤖 Generated with Claude Code


Note

Low Risk
UI-only accessibility and Escape handling; no auth, SQL execution, or data persistence changes.

Overview
Improves screen reader and keyboard behavior for two overlays that were plain divs before.

WriteConfirmDialog now exposes role="dialog", aria-modal="true", and aria-labelledby tied to its dynamic title (e.g. Safe mode: run UPDATE statements?) via useId.

Saved Credentials (CredentialManager) gets the same dialog semantics, names the icon close control Close saved credentials (type="button"), and closes on Escape through a new shared useEscapeKey hook. Escape is disabled while add/edit opens ConnectionModal on top so only the top layer dismisses.

Adds Vitest coverage for dialog role/name and Escape layering; test-id docs note the close button label.

Reviewed by Cursor Bugbot for commit 677a7ed. Bugbot is set up for automated code reviews on this repo. Configure here.

@cursor cursor Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes using default effort and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit bf24fd4. Configure here.

}, [visible]);

// Escape closes the manager, but not while the credential form is open on top.
useEscapeKey(onClose, open && !adding && !editing);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Form layer leaves Escape unhandled

Medium Severity

useEscapeKey is disabled while adding or editing so Escape can close the credential form on top, but ConnectionModal has no Escape handler. After Add or Edit Credential, Escape dismisses neither layer. Users who just used Escape to close Saved Credentials now get no response.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit bf24fd4. Configure here.

huyplb and others added 2 commits November 1, 2026 15:28
…logs; Escape closes Saved Credentials

From the 2026-11-01 manual walk:

- The Safe-mode confirm (sql-write-confirm) and Saved Credentials were
  plain divs: a screen reader was not told a dialog had opened. Both now
  have role="dialog", aria-modal and aria-labelledby on their title.
- Saved Credentials did not close on Escape, unlike the other dialogs,
  and its close button was an unnamed icon. It closes on Escape now, but
  not while the credential form is open on top, and the button is named.

useEscapeKey (shared/lib) is the Escape listener WorkspaceSettingsDialog
and others each write by hand, with an enabled flag for layered dialogs.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@huyplb
huyplb merged commit ea3a3e0 into main Nov 1, 2026
13 checks passed
@huyplb
huyplb deleted the fix/dialog-a11y branch November 1, 2026 21:38
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.

1 participant