[Improvement]: A11y — aria-live regions for chat streaming, updater and git feedback#172
[Improvement]: A11y — aria-live regions for chat streaming, updater and git feedback#172matiaspalmac wants to merge 2 commits intoTrixtyAI:mainfrom
Conversation
…back
Screen readers were silent on four dynamic UI surfaces that announce
completion or error state:
- `AiChatComponent`: the chat transcript had no live region, so
streaming assistant replies and tool-run status never reached AT.
Marked the scroll container as `role=log` / `aria-live=polite` and
toggle `aria-busy` while a response is in flight.
- `UpdaterDialog`: the toast is `role=status` / `aria-live=polite`
normally and escalates to `role=alert` / `aria-live=assertive`
when the updater reports an error.
- `GitExplorerComponent`:
- `gitFeedback` flash banner is now a persistent `role=status`
region (toggled via `sr-only`) instead of being conditionally
mounted, so transient commit/push/stash messages are actually
announced when they appear.
- Merge-conflict banner is `role=alert` so the conflict is
surfaced immediately rather than waiting for focus.
Closes TrixtyAI#105
|
Thanks for the contribution! I'll review it as soon as possible. If you have still changes, please mark this PR as draft and all reviews will be cancelled. Tests reviews will be re-run only when the PR is marked as ready for review. |
There was a problem hiding this comment.
Pull request overview
Adds missing ARIA live regions across key dynamic UI surfaces so screen readers announce chat output, updater status changes, and git feedback/conflict warnings (per issue #105).
Changes:
- Adds
role/aria-livesemantics to the updater toast and git feedback/conflict banners. - Makes the chat transcript container a
role="log"live region witharia-busyduring typing. - Adds a new i18n label (
ai.chat_log_label) in EN/ES for the chat transcript.
Reviewed changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated 1 comment.
| File | Description |
|---|---|
| apps/desktop/src/components/UpdaterDialog.tsx | Wraps updater toast in a live region that escalates to alert semantics on error. |
| apps/desktop/src/addons/builtin.git-explorer/GitExplorerComponent.tsx | Keeps git feedback live region mounted and marks merge conflicts as an assertive alert. |
| apps/desktop/src/addons/builtin.ai-assistant/AiChatComponent.tsx | Marks chat transcript as a polite live log with a localized label and busy state. |
| apps/desktop/src/api/builtin.l10n.ts | Adds ai.chat_log_label translations for EN/ES. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Copilot review on TrixtyAI#172 pointed out that wrapping the whole updater toast in role=status + aria-atomic=true means screen readers re-announce the entire toast (title, buttons, body) every time `progress` ticks — and `updater-progress` fires on every downloaded chunk during install, which can be dozens of events per second. Replaced the toast-wide live region with a single `sr-only` span that carries a pre-formatted phase string (title + status, without the raw progress percentage). Sighted users see the same toast; screen readers now get one announcement per phase change instead of a flood during download, and the role still escalates to `alert` on error.
|
Addressed Copilot review: the previous implementation wrapped the whole toast in Replaced the toast-wide live region with a single |
Description
Screen readers were silent on four dynamic UI surfaces that signal completion or error state. This PR adds the missing ARIA live regions so assistive technologies can hear what sighted users see.
Change
AiChatComponent— the chat transcript scroll container is nowrole="log"/aria-live="polite"witharia-relevant="additions text"andaria-busy={isTyping}. Streaming replies, warnings, and tool-run status are finally announced.UpdaterDialog— the toast isrole="status"/aria-live="polite"during normal phases and escalates torole="alert"/aria-live="assertive"when the updater reports an error, matching user urgency.GitExplorerComponent:gitFeedbackflash banner is now a persistentrole="status"region toggled viasr-onlyinstead of being conditionally mounted — live regions must stay in the DOM before their text changes or the update is missed.role="alert"+aria-live="assertive"so conflicts surface immediately rather than waiting for the user to land focus on that region.ai.chat_log_labeli18n key (EN + ES).Related Issue
Closes #105
Trade-offs
sr-onlywhen empty). That trades a few bytes of markup for reliable screen-reader announcements — keeping the conditional mount would have defeated the purpose of the change for most AT implementations.roleflips betweenstatusandalertbased on phase. Some screen readers announce a role change as a new element, which is the intended effect here (errors should interrupt).Verification
pnpm --filter @trixty/desktop lintpasses clean.npx tsc --noEmitpasses clean.Checklist