[combobox] Support primitive item values#4686
Conversation
commit: |
Bundle size
PerformanceTotal duration: 1,222.22 ms -112.48 ms(-8.4%) | Renders: 50 (+0) | Paint: 1,831.45 ms -210.60 ms(-10.3%)
11 tests within noise — details Check out the code infra dashboard for more information about this PR. |
✅ Deploy Preview for base-ui ready!
To edit notification comments on pull requests, go to your Netlify project configuration. |
d334087 to
9ed7cc6
Compare
There was a problem hiding this comment.
Pull request overview
This PR refactors Select and Combobox to stop storing selectedIndex as synchronized store state and instead derive it from snapshot arrays of item values, enabling closed programmatic value updates without requiring item registration/mounting.
Changes:
- Replace stored
selectedIndexwith derived selectors based onitemValues/allItemValuessnapshots for Select and Combobox. - Remove programmatic value-change force-mounting behavior while keeping autofill/interaction paths working.
- Update Combobox list navigation to use a derived selected item/index (avoiding ref reads during render), and add regression tests.
Reviewed changes
Copilot reviewed 13 out of 13 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
| packages/react/src/select/store.ts | Replace stored selectedIndex with derived selectedIndex computed from itemValues. |
| packages/react/src/select/root/SelectRoot.tsx | Remove programmatic value-change force-mounting; add itemValues state and related behavior. |
| packages/react/src/select/root/SelectRoot.test.tsx | Add regression test ensuring programmatic value changes don’t force-mount the popup. |
| packages/react/src/select/positioner/SelectPositioner.tsx | Remove direct selectedIndex resets when clearing value (now derived). |
| packages/react/src/select/popup/SelectPopup.tsx | Switch selected-index checks to derived selector usage. |
| packages/react/src/select/item/SelectItem.tsx | Maintain itemValues snapshot updates on item mount/unmount; remove direct selectedIndex writes. |
| packages/react/src/combobox/store.ts | Add itemValues/allItemValues snapshots and derive selectedIndex from them. |
| packages/react/src/combobox/root/ComboboxRoot.test.tsx | Add regression tests for deriving/highlighting/scrolling selected item on first open without items. |
| packages/react/src/combobox/root/AriaCombobox.tsx | Remove stored selectedIndex sync logic; maintain snapshots; adjust navigation behavior to use derived selection. |
| packages/react/src/combobox/item/ComboboxItem.tsx | Populate and snapshot itemValues/allItemValues from registered items for derived selection/indexing. |
| packages/react/src/combobox/input/ComboboxInput.tsx | Remove selectedIndex updates from setIndices calls (now derived). |
| packages/react/src/combobox/clear/ComboboxClear.tsx | Remove selectedIndex updates from setIndices calls (now derived). |
| packages/react/src/combobox/chip/ComboboxChip.tsx | Remove selectedIndex updates from setIndices calls (now derived). |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
ccf437d to
95eaa94
Compare
12fb84e to
45b7329
Compare
350c3c1 to
40141a1
Compare
40141a1 to
7c15adb
Compare
1d14d93 to
7ca490a
Compare
7ca490a to
a76c344
Compare
e67fc87 to
95e96a6
Compare
f8837df to
a4c193a
Compare
a4c193a to
97938e3
Compare
Partially addresses #3594.
Related to #4419.
This lets Combobox use primitive values with supported object items, such as
items={[{ value: "banana", label: "Banana" }]}withdefaultValue="banana"or<Combobox.Item value="banana" />.The public API stays the same: Combobox infers primitive values from supported item shapes instead of adding an
itemValueprop. Select is unchanged in this PR.Changes
{ value, label }items.items.Notes
{ value, label }item shape.isItemEqualToValue.