Skip to content

a11y | A17 restore focus on edit cancel - #76

Merged
BrianGenisio merged 2 commits into
mainfrom
fix/a11y-a17-edit-cancel-focus
Aug 12, 2026
Merged

a11y | A17 restore focus on edit cancel#76
BrianGenisio merged 2 commits into
mainfrom
fix/a11y-a17-edit-cancel-focus

Conversation

@BrianGenisio

Copy link
Copy Markdown
Contributor

Summary

Closes #71 (A17). Cancelling a message edit removed the textarea without putting focus back on Edit, so keyboard users landed on <body>.

Changes

  • exitEditMode focuses the Edit button after tearing down the editor (same idea as copyText restoring the trigger).
  • Escape on the editor takes that same cancel path, whether focus is in the textarea or on Cancel/Save.
  • DOM tests cover Cancel click and Escape.

Test plan

  • npm test
  • Keyboard: Tab to Edit, Enter, Escape. Focus should return to Edit.
  • Keyboard: Edit, Tab to Cancel, Enter. Same focus restore.
  • Save still sends; do not expect focus restore on that path.
  • Confirm axe baseline does not grow

Co-authored-by: Cursor <cursoragent@cursor.com>
@coderabbitai

coderabbitai Bot commented Aug 12, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

You’ve reached a temporary PR review limit under our Fair Usage Limits Policy.

Your recent review volume is higher than typical usage, so adaptive limits are currently applied.

Next review available in: 37 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: e44b81e4-6412-4717-a8c1-5f921e66cf1b

📥 Commits

Reviewing files that changed from the base of the PR and between 6d07bc6 and c06cb30.

📒 Files selected for processing (3)
  • a11y-audits/8-5-26/wave-4-plan.md
  • public/app.js
  • tests/dom/render.test.js
📝 Walkthrough

Walkthrough

The edit workflow captures the original Edit button. Cancelling through the Cancel button or Escape removes the textarea and restores focus to that button. DOM tests cover both cancellation paths. The Wave 4 issue map marks A17 and issue 71 as closed.

Possibly related PRs

🚥 Pre-merge checks | ✅ 4
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly identifies the accessibility change: restoring focus when edit cancellation occurs.
Description check ✅ Passed The description accurately explains the focus restoration, Escape handling, tests, and related issue.
Linked Issues check ✅ Passed The changes satisfy issue #71 by restoring focus on cancellation, routing Escape through cancellation, and adding DOM regression tests.
Out of Scope Changes check ✅ Passed The code, tests, and issue-map update are directly related to the A17 focus-restoration objective.

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@tests/dom/render.test.js`:
- Around line 219-220: Update the Escape KeyboardEvent in the test around the
dispatchEvent call to set cancelable: true, retain a reference to the event, and
assert event.defaultPrevented after settle() so the test verifies the Escape
handler prevents the default action.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 6f0715ee-75b2-449b-8391-bcc966b58060

📥 Commits

Reviewing files that changed from the base of the PR and between 323e1f7 and 6d07bc6.

📒 Files selected for processing (3)
  • a11y-audits/8-5-26/wave-4-plan.md
  • public/app.js
  • tests/dom/render.test.js

Comment thread tests/dom/render.test.js
Comment on lines +219 to +220
q('.message__edit-textarea').dispatchEvent(new KeyboardEvent('keydown', { key: 'Escape', bubbles: true }));
await settle();

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Make the Escape event cancelable in the test.

Line 219 creates a non-cancelable KeyboardEvent. The test would pass even if preventDefault() were removed from public/app.js. Set cancelable: true and assert event.defaultPrevented.

This assessment is based on the supplied test and Escape handler code.

Proposed test update
-    q('.message__edit-textarea').dispatchEvent(new KeyboardEvent('keydown', { key: 'Escape', bubbles: true }));
+    const event = new KeyboardEvent('keydown', {
+      key: 'Escape',
+      bubbles: true,
+      cancelable: true,
+    });
+    q('.message__edit-textarea').dispatchEvent(event);
+    expect(event.defaultPrevented).toBe(true);
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
q('.message__edit-textarea').dispatchEvent(new KeyboardEvent('keydown', { key: 'Escape', bubbles: true }));
await settle();
const event = new KeyboardEvent('keydown', {
key: 'Escape',
bubbles: true,
cancelable: true,
});
q('.message__edit-textarea').dispatchEvent(event);
expect(event.defaultPrevented).toBe(true);
await settle();
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/dom/render.test.js` around lines 219 - 220, Update the Escape
KeyboardEvent in the test around the dispatchEvent call to set cancelable: true,
retain a reference to the event, and assert event.defaultPrevented after
settle() so the test verifies the Escape handler prevents the default action.

@BrianGenisio
BrianGenisio merged commit 86fcc05 into main Aug 12, 2026
2 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.

[a11y][A17] Focus not restored when message editing is cancelled

1 participant