-
Notifications
You must be signed in to change notification settings - Fork 760
Add virtualization support for Combobox and ButtonSelect #5812
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: be29ca5ffe
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| if (e.key === "Enter") { | ||
| e.preventDefault(); | ||
| const item = filteredItems[highlightedIndex]; | ||
| if (item) { | ||
| handleSelectItem(item.value, false); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Handle create option on Enter in virtualized combobox
In virtualized mode, Enter always selects filteredItems[highlightedIndex], but the create option is rendered separately and never included in the highlighted index. This means when allowCreation is true and the search text doesn’t match an existing item (showCreateOption), pressing Enter won’t create the new item (it will no-op on an empty list or select the first existing item), which is a regression from the non-virtualized cmdk behavior where the create item is keyboard-selectable.
Useful? React with 👍 / 👎.
| if (e.key === "Enter") { | ||
| e.preventDefault(); | ||
| const item = filteredItems[highlightedIndex]; | ||
| if (item) { | ||
| handleSelectItem(item, false); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Handle create option on Enter in virtualized button select
The virtualized key handler always uses filteredItems[highlightedIndex] on Enter and never considers the create option that appears when creatable is true and the search text is new. As a result, keyboard creation is broken in virtualized mode (Enter does nothing when the filtered list is empty or selects the first existing item instead of creating), which differs from the non-virtualized cmdk behavior.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Cursor Bugbot has reviewed your changes and found 2 potential issues.
Bugbot Autofix is OFF. To automatically fix reported issues with Cloud Agents, enable Autofix in the Cursor dashboard.
| handleSelectItem(item.value, false); | ||
| } | ||
| return; | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Create option unreachable via keyboard in virtualized mode
Medium Severity
The virtualized keyboard Enter handler only accesses filteredItems[highlightedIndex] and always passes isNew: false to handleSelectItem. The "create new" option is rendered separately in ComboboxMenuItems (via its own CommandItem with onSelect={() => onSelectItem(searchValue.trim(), true)}), but highlightedIndex only tracks position within filteredItems. This makes the create option completely unreachable via keyboard navigation when virtualization is active, breaking the VirtualizedWithCreation use case in both components.
Additional Locations (1)
| setHighlightedIndex((prev) => | ||
| Math.min(prev + 8, filteredItems.length - 1), | ||
| ); | ||
| return; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
PageDown sets invalid negative index when list empty
Low Severity
The PageDown handler uses Math.min(prev + 8, filteredItems.length - 1) which returns -1 when filteredItems is empty (since Math.min(8, -1) equals -1). Unlike the End key handler which uses Math.max(0, ...) for protection, and the useEffect which has an explicit if (filteredItems.length === 0) return 0 guard, PageDown lacks empty list handling. This causes highlightedIndex to become -1, resulting in no visual highlighting and Enter doing nothing until the user presses ArrowDown to recover.
Summary
@tanstack/react-virtualfor efficient rendering of large lists (100+ items)virtualizeThresholdprop (default: 100) for bothComboboxandButtonSelectVirtualizedCommandItemscomponent used by both componentsTest plan
Note
Introduces efficient list virtualization for large dropdowns and aligned Storybook coverage.
@tanstack/react-virtualand new sharedVirtualizedCommandItemsto rendercmdklists efficientlyComboboxandButtonSelectwithvirtualizeThreshold(default:100), toggling between virtualized and non-virtualized renderingComboboxMenuItemsto support virtualization and explicit item highlightingui/package.jsonand lockfile to include@tanstack/react-virtualWritten by Cursor Bugbot for commit be29ca5. This will update automatically on new commits. Configure here.