Skip to content

[autocomplete][combobox] Support external items mapping#3594

Draft
atomiks wants to merge 3 commits into
mui:masterfrom
atomiks:fix/autocomplete-external-mapping
Draft

[autocomplete][combobox] Support external items mapping#3594
atomiks wants to merge 3 commits into
mui:masterfrom
atomiks:fix/autocomplete-external-mapping

Conversation

@atomiks

@atomiks atomiks commented Dec 21, 2025

Copy link
Copy Markdown
Contributor

This adds support for the cmdk-style composition pattern without requiring items on Root, and without forcing the filtering/rendering to happen through a function child:

<Combobox.Root>
  <Combobox.Input />
  <Combobox.Portal>
    <Combobox.Positioner>
      <Combobox.Popup>
        <Combobox.List>
          {fruits.map((item) => (
            <Combobox.Item key={item} value={item}>
              <Combobox.ItemIndicator>
                <CheckIcon />
              </Combobox.ItemIndicator>
              <div>{item}</div>
            </Combobox.Item>
          ))}
        </Combobox.List>
      </Combobox.Popup>
    </Combobox.Positioner>
  </Combobox.Portal>
</Combobox.Root>

Before this, Autocomplete could support this shape reasonably well, but filtering had to happen externally. Combobox only had partial support and did not keep selection/highlight/empty-state behavior in sync.

Implementation

  • Combobox.Item filters itself and returns null when it should not be shown.
  • Combobox.Group uses hidden instead of unmounting its children so item registration effects can still run.
  • The rebased version simplifies the bookkeeping a bit by reusing CompositeList metadata for item values instead of maintaining a separate DOM-node-to-value map.

Pros

  • Works with a more composition-oriented API, including server-component-friendly usage where a function child would otherwise need to be hoisted into a client component.
  • TS inference stays natural because the item type comes from the surrounding array.
  • Rendering/order are fully controlled by user composition.

Tradeoffs

Real

  • This is still more internal complexity than the items-driven path.
  • For selection modes with no items, Combobox still needs to force-mount the popup on interaction so labels and selected indices can be registered from the rendered tree.
  • Virtualization still requires items or filteredItems, because unrendered rows are otherwise unknowable.

Not really new / overstated

  • Strings already work fine. Objects are only needed when the value/label are distinct, which is the same existing itemToStringLabel story rather than a new requirement introduced by this approach.
  • Some of the implementation overhead was incidental rather than fundamental; the rebased version trims part of it by removing extra value-mapping plumbing.

Validation

  • pnpm test:jsdom ComboboxRoot --no-watch
  • pnpm test:jsdom AutocompleteRoot --no-watch
  • pnpm typescript
  • pnpm eslint docs/reference/generated/combobox-empty.json packages/react/src/autocomplete/root/AutocompleteRoot.test.tsx packages/react/src/combobox/empty/ComboboxEmpty.tsx packages/react/src/combobox/group/ComboboxGroup.tsx packages/react/src/combobox/group/ComboboxGroupContext.ts packages/react/src/combobox/input/ComboboxInput.tsx packages/react/src/combobox/item/ComboboxItem.tsx packages/react/src/combobox/list/ComboboxList.tsx packages/react/src/combobox/popup/ComboboxPopup.tsx packages/react/src/combobox/positioner/ComboboxPositioner.tsx packages/react/src/combobox/root/AriaCombobox.tsx packages/react/src/combobox/root/ComboboxRoot.test.tsx packages/react/src/combobox/root/ComboboxRootContext.tsx packages/react/src/combobox/store.ts packages/react/src/combobox/trigger/ComboboxTrigger.tsx packages/react/src/composite/list/useCompositeListItem.ts

@atomiks atomiks added type: enhancement It’s an improvement, but we can’t make up our mind whether it's a bug fix or a new feature. component: autocomplete Changes related to the autocomplete component. component: combobox Changes related to the combobox component. labels Dec 21, 2025
@pkg-pr-new

pkg-pr-new Bot commented Dec 21, 2025

Copy link
Copy Markdown

commit: 9b79d6c

@mui-bot

mui-bot commented Dec 21, 2025

Copy link
Copy Markdown

Bundle size report

Bundle Parsed size Gzip size
@base-ui/react 🔺+1.79KB(+0.39%) 🔺+615B(+0.42%)

Details of bundle changes


Check out the code infra dashboard for more information about this PR.

@netlify

netlify Bot commented Dec 21, 2025

Copy link
Copy Markdown

Deploy Preview for base-ui ready!

Name Link
🔨 Latest commit 4e7e58e
🔍 Latest deploy log https://app.netlify.com/projects/base-ui/deploys/69c0de49bd2907000826e317
😎 Deploy Preview https://deploy-preview-3594--base-ui.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

@atomiks atomiks force-pushed the fix/autocomplete-external-mapping branch 5 times, most recently from 3d51da5 to 9204b7b Compare December 22, 2025 01:34
@KingSora

Copy link
Copy Markdown

@atomiks do you think this would also cover the usecase described here: #3559 ?

@github-actions github-actions Bot added the PR: out-of-date The pull request has merge conflicts and can't be merged. label Jan 9, 2026
@atomiks atomiks force-pushed the fix/autocomplete-external-mapping branch from 9204b7b to 9b79d6c Compare February 6, 2026 04:03
@github-actions github-actions Bot added PR: out-of-date The pull request has merge conflicts and can't be merged. and removed PR: out-of-date The pull request has merge conflicts and can't be merged. labels Feb 6, 2026
@github-actions github-actions Bot removed the PR: out-of-date The pull request has merge conflicts and can't be merged. label Feb 17, 2026
@github-actions github-actions Bot added the PR: out-of-date The pull request has merge conflicts and can't be merged. label Mar 11, 2026
@atomiks atomiks force-pushed the fix/autocomplete-external-mapping branch from 3bf75f9 to 4e7e58e Compare March 23, 2026 06:31
@github-actions github-actions Bot added PR: out-of-date The pull request has merge conflicts and can't be merged. and removed PR: out-of-date The pull request has merge conflicts and can't be merged. labels Mar 23, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

component: autocomplete Changes related to the autocomplete component. component: combobox Changes related to the combobox component. PR: out-of-date The pull request has merge conflicts and can't be merged. type: enhancement It’s an improvement, but we can’t make up our mind whether it's a bug fix or a new feature.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants