Skip to content

fix(chat): keep the slash command selection visible and valid on long or filtered lists - #499

Merged
mbektas merged 3 commits into
plmbr:mainfrom
FelipeRamos-neuro:fix/slash-popover-arrow-scroll
Sep 24, 2026
Merged

mbektas merged 3 commits into
plmbr:mainfrom
FelipeRamos-neuro:fix/slash-popover-arrow-scroll

Conversation

@FelipeRamos-neuro

Copy link
Copy Markdown
Contributor

Summary

Fixes keyboard navigation of the slash / @ command popover on long or filtered lists.

Closes #498

Problem

  1. The popover scrolls when it has more commands than fit, but the arrow keys only moved the selection, so the highlight walked out of view. The rest of the list was reachable only with the mouse wheel, and ArrowUp from the first row wrapped to a hidden last row.
  2. The selected index outlives the list it was chosen from. Arrow down to row 20 of 33, then type something that leaves one match: the index points past the end, no row is highlighted, and Enter calls applyPrefixSuggestion(undefined). That throws (Cannot read properties of undefined (reading 'startsWith')) and swallows the keypress. This is the same class of problem as the "Enter with an unmatched @ or /" fix (fix(chat): let Enter send a message that starts with an unmatched @ or / #464).

Solution

  • scrollSelectedSuggestionIntoView scrolls the selected row into view with block: 'nearest' whenever the selection changes, including on wrap-around. nearest scrolls by the smallest amount and does nothing when the row is already visible.
  • filterPrefixSuggestions resets the selection to the first row, since a narrowed list is a different list.
  • activeSuggestionIndex(selected, count) returns the index if it still points at a row and 0 otherwise. Enter, Tab, both arrow keys, the highlight class and the scroll effect all read the index through it, so no other path that shrinks the list can leave it dangling.

Two commits: the scroll fix, then the stale-index fix.

How to test

I checked this by hand in JupyterLab, on main and on this branch, with a small test extension that adds a participant @many with 30 commands, so the popover has 33 rows in Ask mode. The full extension source and steps are in #498. In short:

  • Scroll: type /, press ArrowDown 20+ times. On main the highlight leaves the visible list; on this branch it follows the selection, including the wrap from last to first and back.
  • Stale index: type /, ArrowDown about 20 times, type cmd30, press Enter. On main nothing is highlighted, Enter does nothing and the console shows the TypeError. On this branch the single match is highlighted and Enter completes it.

Both symptoms reproduce on main and are resolved on this branch.

Testing

  • tests/ts/chat-prefix-suggestions.test.ts covers scrollSelectedSuggestionIntoView (only the selected row is scrolled, wrap-around, missing popover / out-of-range index / no scrollIntoView) and activeSuggestionIndex (valid, out-of-range, negative and empty lists, and the exact narrowed-list scenario). If the helper returned the raw index, 3 of the new tests fail.
  • The scroll behaviour was also checked in headless Chrome with the real base.css layout: with the fix, no selected row left the popover in any of the sizes tried (0 rows off-screen, against 26, 36 and 4 without it).
  • jlpm jest (583 passed), jlpm tsc --noEmit, jlpm lint:check and pytest tests/ (2221 passed) are clean.

Not covered by an automated test: the reset in filterPrefixSuggestions itself, because there is no component test harness for ChatSidebar. The helper is the safety net for it, and the manual test above exercises the reset.

Not checked: Firefox, macOS, and Claude or ACP mode. Their command lists are built from a different source, but they use the same popover.

🤖 Generated with Claude Code

FelipeRamos-neuro and others added 2 commits September 21, 2026 18:15
The suggestion popover scrolls when it holds more commands than fit, but the
arrow keys only moved the selection, so it walked out of view and the rest of
the list was reachable only with the mouse wheel. Scroll the selected row into
view with block: nearest whenever the selection changes, including when it
wraps from the first row to the last.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…ring

The selected index is state that outlives the list it was chosen from. Arrow
down to row 12 of 30, then type a character that narrows the list to 3, and
the index points past the end: no row is highlighted, and Enter applies an
undefined suggestion, which throws in applyPrefixSuggestion and swallows the
keypress.

Reset the selection to the first row whenever the filter changes, and read it
through activeSuggestionIndex, which falls back to the first row for any index
that no longer points at one, so no other path that shrinks the list can leave
it dangling.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@pjdoland pjdoland added the bug Something isn't working label Sep 22, 2026
@mbektas
mbektas merged commit ee285a5 into plmbr:main Sep 24, 2026
4 checks passed
@FelipeRamos-neuro
FelipeRamos-neuro deleted the fix/slash-popover-arrow-scroll branch September 25, 2026 14:47
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Slash command list: keyboard navigation breaks on long or filtered lists

3 participants