Skip to content

fix(a11y): keep composer focusable while streaming - #46

Merged
BrianGenisio merged 1 commit into
mainfrom
fix/a11y-a3-composer-readonly
Aug 7, 2026
Merged

fix(a11y): keep composer focusable while streaming#46
BrianGenisio merged 1 commit into
mainfrom
fix/a11y-a3-composer-readonly

Conversation

@BrianGenisio

Copy link
Copy Markdown
Contributor

Summary

  • Stop disabling the prompt textarea while a reply streams. Use readOnly so the composer stays focusable and in the accessibility tree (A3).
  • Pair the transient wait with aria-describedby pointing at a short explanation (#promptInputBusyHint, via t() / en+es).
  • If focus has fallen to <body>/documentElement when the stream ends, return it to the composer. Do not steal focus if the user moved elsewhere (e.g. Stop).

Closes #44

Changes

renderMessages calls a small syncComposerAvailability(streaming) helper instead of promptInput.disabled = streaming. Disabling a focused control was what dropped keyboard users to <body> on every send. readOnly blocks typing without removing the field from the tab order; Enter still cannot send mid-stream because isComposerSendAllowed() already gates on streaming status.

DOM harness coverage asserts readOnly/disabled, aria-describedby wiring, focus survival across a fake stream tick, and focus restore from <body> on idle. A1/A2/A11 reconciliation and the persistent #chatStatus region are untouched.

Test plan

  • npm test — 183 passed (includes 3 new A3 cases)
  • npm run build + server on PORT=3100; A11Y_CI=1 A11Y_BASE_URL=http://127.0.0.1:3100 npm run audit in a11y-audits/tools — axe baseline gate passed (no shrink needed)
  • Browser check (light + dark via prefers-color-scheme): composer stays focused under readOnly; focus restores from <body> when cleared
  • Manual keyboard walkthrough with a live agent: Tab to composer → type → Enter → confirm focus stays through stream → confirm can Tab to Stop → on complete, typing works again

Use readOnly instead of disabled so focus is not dropped to body mid-stream, explain the wait via aria-describedby, and restore focus on completion if it was lost.

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

coderabbitai Bot commented Aug 7, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 709f01d6-c7eb-4fdf-ab24-b38f55e1f573

📥 Commits

Reviewing files that changed from the base of the PR and between 032b84e and fe48b20.

📒 Files selected for processing (5)
  • i18n/en.json
  • i18n/es.json
  • public/app.js
  • public/index.html
  • tests/dom/render.test.js

📝 Walkthrough

Walkthrough

The composer no longer becomes disabled while Cosmo streams a response. It stays focusable and becomes read-only. A localized accessibility hint describes the temporary state through aria-describedby. The composer removes the hint after streaming and restores focus when focus has moved to the document body. English and Spanish translations, hidden hint markup, and DOM accessibility tests were added.

Possibly related PRs

Fixed issue severity: Medium

🚥 Pre-merge checks | ✅ 4
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes the main accessibility change: keeping the composer focusable during streaming.
Description check ✅ Passed The description accurately explains the composer, ARIA, focus restoration, localization, tests, and accessibility audit changes.
Linked Issues check ✅ Passed The changes satisfy issue #44 by replacing disabled with readOnly, adding the busy hint, preserving focus, and restoring focus when needed.
Out of Scope Changes check ✅ Passed All changes are directly related to issue #44 and its composer accessibility requirements.

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

@BrianGenisio
BrianGenisio merged commit 58ff369 into main Aug 7, 2026
1 of 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][A3] Composer disabled mid-stream drops focus to body

1 participant