[PR #22091] [CLOSED] fix: add accessible labels and live regions to chat UI #65331

Closed
opened 2026-05-06 11:07:08 -05:00 by GiteaMirror · 0 comments
Owner

📋 Pull Request Information

Original PR: https://github.com/open-webui/open-webui/pull/22091
Author: @devinprater
Created: 3/1/2026
Status: Closed

Base: devHead: fix/unlabeled-controls


📝 Commits (3)

  • d3b9b19 fix: add accessible labels and live regions to chat UI
  • 99d644b fix: correct JS escape sequences in markdownToPlainText
  • a54f37b fix: label More and Integrations toolbar buttons

📊 Changes

10 files changed (+2303 additions, -2140 deletions)

View changed files

📝 src/lib/components/chat/MessageInput.svelte (+13 -2)
📝 src/lib/components/chat/Messages.svelte (+101 -4)
📝 src/lib/components/chat/Messages/Message.svelte (+9 -1)
📝 src/lib/components/chat/Messages/ResponseMessage.svelte (+7 -4)
📝 src/lib/components/chat/ModelSelector/ModelItem.svelte (+11 -3)
📝 src/lib/components/chat/ModelSelector/Selector.svelte (+9 -1)
📝 src/lib/components/chat/Navbar.svelte (+5 -1)
📝 src/lib/i18n/locales/en-US/translation.json (+2131 -2123)
📝 src/lib/stores/index.ts (+7 -0)
📝 src/routes/+layout.svelte (+10 -1)

📄 Description

Pull Request Checklist

  • Target branch: This PR targets the dev branch.
  • Description: See changelog below.
  • Changelog: Included below.
  • Documentation: No new user-facing settings or APIs introduced.
  • Dependencies: No new dependencies.
  • Testing: Changes are additive ARIA attributes and sr-only elements; no visual regressions. Tested with NVDA + Firefox and keyboard-only navigation.
  • Agentic AI Code: This PR was authored with AI assistance and has been manually reviewed.
  • Code review: Self-reviewed.
  • Design & Architecture: All changes are accessibility-only; no UX or architectural changes.
  • Git Hygiene: Single atomic commit targeting dev.
  • Title Prefix: fix:

Changelog Entry

Description

Fixes 11 WCAG 4.1.2 (Name, Role, Value) violations where icon-only buttons, toggle controls, and interactive elements lacked accessible names. Also adds a proper combobox ARIA pattern to the model selector and global aria-live regions so screen readers announce AI response generation status and completed responses.

Fixed

  • MessageInput.svelte — Scroll-to-bottom button, dismiss @-model button, Web Search toggle, Image Generation toggle, Stop generating button, and Send message button all lacked aria-label. Web Search and Image Generation toggles also lacked aria-pressed to communicate their on/off state.
  • Navbar.svelte — Mobile sidebar toggle had no aria-label. Controls button had a hard-coded English aria-label that did not translate with the UI language.
  • ResponseMessage.svelte — Token usage info button had aria-hidden="true" on a focusable element (keyboard users could tab to it but hear nothing). Regenerate menu trigger was a non-interactive <div> with no keyboard activation.
  • MessageInput.svelte hidden trigger button: add aria-hidden="true" to exclude it from the accessibility tree.

Added

  • Selector.svelte — Model search input now has role="combobox", aria-expanded, aria-controls, and aria-activedescendant so screen readers correctly describe the dropdown relationship. e.preventDefault() added to ArrowUp/ArrowDown to prevent page scroll during keyboard navigation.
  • ModelItem.svelte — Model list items changed from <button> to <div role="option" tabindex="-1" id="model-option-{index}"> to correctly participate in the combobox/listbox pattern. aria-label simplified to item.label. Keyboard handler added for Enter/Space.
  • Message.svelte — Screen-reader-only <h3> headings added before each message block so users can skim the conversation by heading level ("You said:", "[Model name] said:", "Assistants said:").
  • Messages.svelte + stores/index.ts + +layout.svelte — Global aria-live regions placed outside all content areas (in the document root via +layout.svelte) so NVDA browse-mode navigation never lands on them. Messages.svelte writes generation status ("Generating response…" / "Still generating…" every 6 s) and the completed plain-text response to global Svelte stores. The live region fires on response completion and during streaming.
  • en-US/translation.json — 8 new i18n keys registered for the new aria-label values.

Breaking Changes

  • None.

Additional Information

  • The <ul role="log"> that previously surrounded the message list has been changed to a plain <div> because the live region responsibility moved to the global aria-live regions in +layout.svelte. Keeping role="log" on the list would cause double-announcements.
  • The hidden #generate-message-pair-button is a programmatic trigger (not user-facing); aria-hidden="true" ensures AT does not enumerate it.

Screenshots or Videos

No visual changes (all modifications are ARIA attributes and sr-only elements).

Contributor License Agreement

By submitting this pull request, I confirm that I have read and fully agree to the Contributor License Agreement (CLA), and I am providing my contributions under its terms.


🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.

## 📋 Pull Request Information **Original PR:** https://github.com/open-webui/open-webui/pull/22091 **Author:** [@devinprater](https://github.com/devinprater) **Created:** 3/1/2026 **Status:** ❌ Closed **Base:** `dev` ← **Head:** `fix/unlabeled-controls` --- ### 📝 Commits (3) - [`d3b9b19`](https://github.com/open-webui/open-webui/commit/d3b9b191b7c12b8a2d6cc01891aa23b88cdb8b52) fix: add accessible labels and live regions to chat UI - [`99d644b`](https://github.com/open-webui/open-webui/commit/99d644b56a5e7084221b55107b773c6f6fd52114) fix: correct JS escape sequences in markdownToPlainText - [`a54f37b`](https://github.com/open-webui/open-webui/commit/a54f37b16e5720e936321c31e76de5293ad2c41c) fix: label More and Integrations toolbar buttons ### 📊 Changes **10 files changed** (+2303 additions, -2140 deletions) <details> <summary>View changed files</summary> 📝 `src/lib/components/chat/MessageInput.svelte` (+13 -2) 📝 `src/lib/components/chat/Messages.svelte` (+101 -4) 📝 `src/lib/components/chat/Messages/Message.svelte` (+9 -1) 📝 `src/lib/components/chat/Messages/ResponseMessage.svelte` (+7 -4) 📝 `src/lib/components/chat/ModelSelector/ModelItem.svelte` (+11 -3) 📝 `src/lib/components/chat/ModelSelector/Selector.svelte` (+9 -1) 📝 `src/lib/components/chat/Navbar.svelte` (+5 -1) 📝 `src/lib/i18n/locales/en-US/translation.json` (+2131 -2123) 📝 `src/lib/stores/index.ts` (+7 -0) 📝 `src/routes/+layout.svelte` (+10 -1) </details> ### 📄 Description # Pull Request Checklist - [x] **Target branch:** This PR targets the `dev` branch. - [x] **Description:** See changelog below. - [x] **Changelog:** Included below. - [ ] **Documentation:** No new user-facing settings or APIs introduced. - [x] **Dependencies:** No new dependencies. - [x] **Testing:** Changes are additive ARIA attributes and sr-only elements; no visual regressions. Tested with NVDA + Firefox and keyboard-only navigation. - [x] **Agentic AI Code:** This PR was authored with AI assistance and has been manually reviewed. - [x] **Code review:** Self-reviewed. - [x] **Design & Architecture:** All changes are accessibility-only; no UX or architectural changes. - [x] **Git Hygiene:** Single atomic commit targeting `dev`. - [x] **Title Prefix:** `fix:` --- # Changelog Entry ### Description Fixes 11 WCAG 4.1.2 (Name, Role, Value) violations where icon-only buttons, toggle controls, and interactive elements lacked accessible names. Also adds a proper combobox ARIA pattern to the model selector and global `aria-live` regions so screen readers announce AI response generation status and completed responses. ### Fixed - `MessageInput.svelte` — Scroll-to-bottom button, dismiss @-model button, Web Search toggle, Image Generation toggle, Stop generating button, and Send message button all lacked `aria-label`. Web Search and Image Generation toggles also lacked `aria-pressed` to communicate their on/off state. - `Navbar.svelte` — Mobile sidebar toggle had no `aria-label`. Controls button had a hard-coded English `aria-label` that did not translate with the UI language. - `ResponseMessage.svelte` — Token usage info button had `aria-hidden="true"` on a focusable element (keyboard users could tab to it but hear nothing). Regenerate menu trigger was a non-interactive `<div>` with no keyboard activation. - `MessageInput.svelte` hidden trigger button: add `aria-hidden="true"` to exclude it from the accessibility tree. ### Added - `Selector.svelte` — Model search input now has `role="combobox"`, `aria-expanded`, `aria-controls`, and `aria-activedescendant` so screen readers correctly describe the dropdown relationship. `e.preventDefault()` added to ArrowUp/ArrowDown to prevent page scroll during keyboard navigation. - `ModelItem.svelte` — Model list items changed from `<button>` to `<div role="option" tabindex="-1" id="model-option-{index}">` to correctly participate in the combobox/listbox pattern. `aria-label` simplified to `item.label`. Keyboard handler added for Enter/Space. - `Message.svelte` — Screen-reader-only `<h3>` headings added before each message block so users can skim the conversation by heading level ("You said:", "[Model name] said:", "Assistants said:"). - `Messages.svelte` + `stores/index.ts` + `+layout.svelte` — Global `aria-live` regions placed outside all content areas (in the document root via `+layout.svelte`) so NVDA browse-mode navigation never lands on them. `Messages.svelte` writes generation status ("Generating response…" / "Still generating…" every 6 s) and the completed plain-text response to global Svelte stores. The live region fires on response completion and during streaming. - `en-US/translation.json` — 8 new i18n keys registered for the new `aria-label` values. ### Breaking Changes - None. --- ### Additional Information - The `<ul role="log">` that previously surrounded the message list has been changed to a plain `<div>` because the live region responsibility moved to the global `aria-live` regions in `+layout.svelte`. Keeping `role="log"` on the list would cause double-announcements. - The hidden `#generate-message-pair-button` is a programmatic trigger (not user-facing); `aria-hidden="true"` ensures AT does not enumerate it. ### Screenshots or Videos No visual changes (all modifications are ARIA attributes and `sr-only` elements). ### Contributor License Agreement By submitting this pull request, I confirm that I have read and fully agree to the [Contributor License Agreement (CLA)](https://github.com/open-webui/open-webui/blob/main/CONTRIBUTOR_LICENSE_AGREEMENT), and I am providing my contributions under its terms. --- <sub>🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.</sub>
GiteaMirror added the pull-request label 2026-05-06 11:07:08 -05:00
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: github-starred/open-webui#65331