anthropics / anthropics/claude-code
[BUG] Claude Code Desktop (Windows): slash command menu in the Code tab composer is silent for screen readers (NVDA)
- Vorherrschende Sprache
- Python
- Sterne
- 145k
- Forks
- 23.1k
- PR-Merge-Kennzahlen
- PR-Kennzahlen ausstehend
Beschreibung
### Preflight Checklist
- [x] I have searched [existing issues](https://github.com/anthropics/claude-code/issues?q=is%3Aissue%20state%3Aopen%20label%3Abug) 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
```shell
None; this is an accessibility-tree problem.
```
### Steps to Reproduce
1. On Windows 11, start NVDA and open Claude Desktop → Code tab, with a Claude Code session.
2. Focus the prompt composer and type `/ren`.
3. Press ArrowDown/ArrowUp a few times, then press Enter or Tab.
4. 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)
1. **Focus stays in the editor, and the editor does not reference the menu.** The menu is a TipTap suggestion plugin (`slash-command-suggestion`, `char:"/"`) in `shared-13-D4O01Gj8.js`. On mount the menu calls `i.view.dom.focus()`, so DOM focus stays in the ProseMirror contenteditable. That element never gets `role="combobox"`, `aria-expanded`, `aria-controls`/`aria-owns` or `aria-activedescendant`: none of these attributes occur in that file. The popup element is appended straight to `document.body` (`...ownerDocument.body.appendChild(o)`), with no relationship to the editor in the accessibility tree.
2. **The highlighted row is only highlighted visually.** In the lazy chunk `ccc334009-BDcyQYO5.js` (`SlashCommandMenuPopupBody`) each row is `role:"menuitem", tabIndex:-1` with `"data-highlighted": n ? "" : void 0`. Rows have no `id` and no `aria-selected`, and never receive focus. The active row element is tracked (`setActiveRowElement`) only to `scrollIntoView` it. The container in `shared-12-BzDv77xE.js` is a `role:"menu"` div without an `id` or accessible name. Long lists are virtualised (`getVirtualItems()`), so the highlighted row may not be in the DOM until scrolled to.
3. **Navigation keys are swallowed before the screen reader can observe a change.** The menu provider (`OL`, "useSlashCommandMenu", `shared-12-BzDv77xE.js`) adds a capture-phase `keydown` listener on the document (`s.addEventListener("keydown",B,!0)`). For ArrowUp/Down/Left/Right, Tab and Enter it calls `preventDefault()` and `stopImmediatePropagation()` and only updates React state (`activeIndex`). The suggestion plugin's `onKeyDown` in `shared-13` also returns `true` for these keys while items are visible. Neither the caret, the focus nor `aria-activedescendant` changes, so NVDA has nothing to announce.
4. **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.
5. **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 keep `textbox` and add the combobox attributes), `aria-haspopup="listbox"`, `aria-autocomplete="list"`, `aria-expanded` bound to the menu state, and `aria-controls` pointing to the menu's id (TipTap: `editorProps.attributes`, or set them in the suggestion's `onStart`/`onExit`).
- Popup `role="listbox"` with an id and an accessible name ("Commands"); rows `role="option"` with a stable `id` and `aria-selected`; keep `aria-activedescendant` on the editor in sync with `activeIndex` (and the submenu index). The `/resume` picker (`cli-resume-listbox`, `cli-resume-opt-N`) and the `/rewind` list (`rewind-opt-N`) in `c5610fbe3-0RHH64gR.js` already 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-activedescendant` changes 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.
Beitragsleitfaden
Für dieses Repository ist kein Beitragsleitfaden indexiert
Bewertung
Dieses Issue wurde noch nicht bewertet.