Make topic tabs accessible to screen readers - #31110
Open
rezabakhshilaktasaraei wants to merge 7 commits into
Open
Make topic tabs accessible to screen readers#31110rezabakhshilaktasaraei wants to merge 7 commits into
rezabakhshilaktasaraei wants to merge 7 commits into
Conversation
rezabakhshilaktasaraei
force-pushed
the
subsection-tabs-accessibility
branch
2 times, most recently
from
August 5, 2026 05:00
534b1e1 to
36f9dfc
Compare
rezabakhshilaktasaraei
force-pushed
the
subsection-tabs-accessibility
branch
from
August 26, 2026 03:05
36f9dfc to
e3969f4
Compare
The strip is called tabs everywhere in the UI, its position toggle included, so a screen reader should call its items tabs as well. The browsing stays as it was - arrows move between tabs and Enter switches - matching how a tab list whose panes load their content is supposed to behave. The folders sidebar keeps being a list: its locked folders fit plain list items better than tabs that refuse to become current.
The buttons of ComposeControls are created in an order unrelated to where they sit in the row (the send button first of all), so switching to a topic scrambled the Tab chain that HistoryWidget already keeps in layout order. Also name the send-as button the way HistoryWidget names its own.
Browsing with the arrows used to leave the roving Tab stop on the last browsed tab, so Tabbing back into the strip landed there instead of on the current topic. Once focus leaves the strip, the stop parks back on the active tab, the way the chat folder tabs behave.
The context menu key picked the right topic but popped the menu at the mouse cursor, which may sit nowhere near the tab or outside the window altogether. The slider now sends the position to show the menu at along with the section index - the tab itself for a keyboard-invoked menu, the cursor as before for a mouse-invoked one.
The chat list already reports pinned chats as pinned; the pinned tabs of the strip conveyed it only by their ordering. The tab name carries the same pinned mark now.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The topic tabs inside a forum chat (and the sender tabs in a channel's Direct Messages inbox) were invisible to screen readers: the tab buttons had no names, no list semantics and no keyboard access, so a blind user could not tell which topics exist, which one is active, or switch between them.
The tab strip is now a tab control - it is named tabs everywhere in the UI, so the screen reader calls it that too. Each tab is a named item (title with unread count, mention state and the pinned mark, updated as the badges change), the active one is reported as selected, and the strip is named "Topics" or "Direct Messages" with the right orientation for each position. In screen reader mode the strip gets one roving Tab stop on the active tab; arrows move focus between tabs (Up/Down when vertical, Left/Right when horizontal, Home/End for the edges) without switching - the browse-then-commit pattern for tabs whose panes load their content - Enter or Space activates, the context menu key opens the topic menu anchored on the tab (a mouse-invoked menu keeps opening at the cursor), and the focused tab is scrolled into view. Keyboard focus survives the frequent rebuilds of the strip on unread updates. The folders sidebar follows in #31176.
The position toggle button got an accessible name, with the current position reported in its description. It is also one persistent widget now, reused across mode switches instead of being recreated with the strip, so pressing it from the keyboard keeps focus on it without the screen reader re-announcing the button on every press. Sighted users are unaffected - the button is only focusable in screen reader mode.
The strip is created only once it is needed, long after the top bar, the list and the composer, so its Tab stops used to land at the end of the chain. The chat sections now keep their Tab chain in visual order (the lib_ui visual Tab order added for the chat list column), which places the strip at its reading-order position wherever it sits - left column, top or bottom - and follows it as the toggle moves it around. The one thing the container cannot see on its own is the roving stop moving between tabs deep inside the strip, so the slider tells it after each move; without that, a Tab entering the strip from outside would follow wiring to the previous stop. The composer inside a topic needed the same treatment: its buttons are created in an order unrelated to the row layout, so switching topics used to scramble their Tab order, and its send-as picker was missing its accessible name.
Needs desktop-app/lib_ui#348 for the PageTab button role.
Tested with NVDA on Windows 10 in a forum group with the tabs layout: browsing, activation, unread counts, context menus and cycling the tab bar through all three positions - after each move the next Tab finds the strip at its new place, and leaving the strip and Tabbing back in lands on the active tab - the arrows browse freely inside, but once focus leaves, the roving stop parks back on the current topic.