[BUG] Claude Code Desktop (Windows): slash command menu in the Code tab composer is silent for screen readers (NVDA)
Preflight Checklist
- [x] I have searched existing issues and this hasn't been reported yet
- [x] This is a single bug report (please file separate reports for different bugs)
- [x] I am using the latest version of Claude Code
What's Wrong?
In Claude Code Desktop (the Code tab of Claude Desktop 1.52386.6.0 on Windows 11, Claude Code 2.1.270), the slash command menu that opens when typing / in the prompt composer (for example /rename) is completely silent for the NVDA screen reader. NVDA announces nothing when the menu opens, nothing while arrowing through it, and not which command is highlighted. Because ArrowUp/Down, Tab and Enter are taken over by the menu, a blind user cannot tell what Enter or Tab will do, so entering a command such as /rename New title becomes guesswork.
What Should Happen?
The composer exposes the menu as an autocomplete popup (ARIA 1.2 combobox pattern): NVDA announces that suggestions are available, reads the highlighted command and its description as the arrow keys move, and Enter/Tab behave predictably (WCAG 4.1.2 Name, Role, Value; 1.3.1 Info and Relationships; 4.1.3 Status Messages). The /resume and /rewind pickers in the same app already do this correctly.
Error Messages/Logs
None; this is an accessibility-tree problem.
Steps to Reproduce
- On Windows 11, start NVDA and open Claude Desktop → Code tab, with a Claude Code session.
- Focus the prompt composer and type
/ren. - Press ArrowDown/ArrowUp a few times, then press Enter or Tab.
- Observe: NVDA says nothing at any step; the menu is only visible on screen.
Claude Model
Opus
Is this a regression?
I don't know
Last Working Version
_No response_
Claude Code Version
2.1.270 (Claude Code), bundled with Claude Desktop 1.52386.6.0
Platform
Anthropic API
Operating System
Windows
Terminal/Shell
Other (Claude Code Desktop, Code tab)
Additional Information
Root cause (from the shipped bundle resources/ion-dist/assets/v1/, minified names)
- Focus stays in the editor, and the editor does not reference the menu. The menu is a TipTap suggestion plugin (
slash-command-suggestion,char:"/") inshared-13-D4O01Gj8.js. On mount the menu callsi.view.dom.focus(), so DOM focus stays in the ProseMirror contenteditable. That element never getsrole="combobox",aria-expanded,aria-controls/aria-ownsoraria-activedescendant: none of these attributes occur in that file. The popup element is appended straight todocument.body(...ownerDocument.body.appendChild(o)), with no relationship to the editor in the accessibility tree. - The highlighted row is only highlighted visually. In the lazy chunk
ccc334009-BDcyQYO5.js(SlashCommandMenuPopupBody) each row isrole:"menuitem", tabIndex:-1with"data-highlighted": n ? "" : void 0. Rows have noidand noaria-selected, and never receive focus. The active row element is tracked (setActiveRowElement) only toscrollIntoViewit. The container inshared-12-BzDv77xE.jsis arole:"menu"div without anidor accessible name. Long lists are virtualised (getVirtualItems()), so the highlighted row may not be in the DOM until scrolled to. - Navigation keys are swallowed before the screen reader can observe a change. The menu provider (
OL, "useSlashCommandMenu",shared-12-BzDv77xE.js) adds a capture-phasekeydownlistener on the document (s.addEventListener("keydown",B,!0)). For ArrowUp/Down/Left/Right, Tab and Enter it callspreventDefault()andstopImmediatePropagation()and only updates React state (activeIndex). The suggestion plugin'sonKeyDowninshared-13also returnstruefor these keys while items are visible. Neither the caret, the focus noraria-activedescendantchanges, so NVDA has nothing to announce. - No live-region fallback. Nothing announces "menu opened", the result count or the highlighted item. The only live region in this area is the skill argument hint (
data-skill-arg-hint-sr); the "Type to filter" hint ($D) is a purely visual span. - Enter/Tab depend on state the user cannot perceive. In
OL's key handler Tab always activates the highlighted row; Enter either activates it or only closes the menu, depending on whether the user navigated with the arrows and whether the highlighted row matches the typed text (e.key==="Enter"&&D===0&&!O&&!A&&(...)?r()). Typed skills are also auto-resolved on a timer once a space follows a unique match (claudeai.slash_command_menu.auto_resolved).
Suggested fix
- On the ProseMirror contenteditable while the menu is open:
role="combobox"(or keeptextboxand add the combobox attributes),aria-haspopup="listbox",aria-autocomplete="list",aria-expandedbound to the menu state, andaria-controlspointing to the menu's id (TipTap:editorProps.attributes, or set them in the suggestion'sonStart/onExit). - Popup
role="listbox"with an id and an accessible name ("Commands"); rowsrole="option"with a stableidandaria-selected; keeparia-activedescendanton the editor in sync withactiveIndex(and the submenu index). The/resumepicker (cli-resume-listbox,cli-resume-opt-N) and the/rewindlist (rewind-opt-N) inc5610fbe3-0RHH64gR.jsalready implement this pattern. - Keep the active option in the DOM whenever it is referenced (virtualised list).
- Add a polite live region with the result count when the menu opens or the filter changes, since
aria-activedescendantchanges on a contenteditable are not always announced by Chromium + NVDA. - Make Enter predictable: when the user has not navigated and the typed text is a complete command with arguments (
/rename New title), submit the text as typed.
Notes
The root cause was established by reading the shipped bundle; the symptom is reproduced by the reporter with NVDA. No live instrumentation was run. Related report by the same reporter about focus handling in Claude Code Desktop: #94246.
Showing cached comments. Read the full discussion on GitHub ↗
3 Comments
Issue is still open in today's update Claude 2.110.0 (dfb2ba) 2026-09-15T05:50:55.000Z
Confirming this on Windows 11 with NVDA 2026.x and Claude Desktop (Code tab). While waiting for a proper fix, I built a local NVDA app module workaround. Here are the findings in case they help the fix:
/menu opens, Chromium firesmenuPopupStartfor therole="menu"container (div.z-dropdown, portalled underdiv.cds-root). NVDA then moves its focus to that menu. It has no accessible name, so NVDA says nothing, and arrow keys no longer reach the composer.role="menuitem"with onlydata-highlighted. They have identical classes, noaria-selectedand no active descendant, so no state change is exposed. The only signal that reaches the accessibility tree is the effectivebackground-colorin the IA2 text attributes:rgb(49,49,48)for the highlighted row andrgb(32,32,31)for the others (dark theme).The workaround reads the highlighted row's background colour, which is fragile and depends on the theme. The real fix is still what this issue proposes:
aria-activedescendanton the composer,role="option"with stable ids andaria-selectedon each row, and an accessible name on the list.Confirming on macOS 27.0.1 with VoiceOver, Claude Desktop 2.26454.0 (Code tab). So this isn't Windows/NVDA-only.
Reproduced by typing
/into the composer and pressing Down Arrow four times. VoiceOver announced nothing at any step, and both the VoiceOver cursor and keyboard focus stayed on the prompt text area.The macOS accessibility tree (read via
AXUIElementwhile the menu was open) matches the analysis above:AXTextArea, description "Prompt") reportsAXHasPopup = 0andAXExpanded = 0, and has noAXOwns,AXControlsor active-descendant attribute.AXMenuItemelements titled with the bare command name.AXDescriptionis empty, so the description text never reaches VoiceOver.AXSelected = 0after arrowing. The highlight shows only as thedata-[highlighted]:bg-fill-ghost-hoverclass.AXGroups with no menu or list container, so there's no item count and nothing to interact into.I couldn't find an older build to compare, so I can't say whether this ever worked.