Bug report
Note: This bug was discovered and diagnosed with the assistance of an AI coding agent (Claude). The source analysis, minimal reproduction, and write-up were largely AI-generated, though reviewed and edited by a human before filing.
Problem
Passing filter={null} to <Autocomplete.Root> does not disable filtering. Instead, the default contains filter is silently applied, causing items to be filtered against the input text. This makes some forms of of server-side search unusable with the Autocomplete component when the input text doesn't substring-match the item labels (e.g., searching against multiple fields).
I later realized that filteredItems was a better approach for the server side filtering use case, but this is still a bug for the filter.
Root cause
In AutocompleteRoot.tsx, the filter prop is checked with a truthiness test:
const baseFilter = React.useMemo(() => {
if (other.filter) { // ← null is falsy, so this branch is skipped
return other.filter;
}
return collator.contains; // ← falls through to default filter
}, [other.filter, collator]);
null is falsy in JavaScript, so if (other.filter) evaluates to false, and baseFilter is set to collator.contains (the default case-insensitive string filter). The user's filter={null} is silently discarded.
By contrast, the underlying AriaCombobox primitive handles this correctly:
const filter = React.useMemo(() => {
if (filterProp === null) { // ← explicit null check
return () => true;
}
// ...
}, [...]);
But AriaCombobox never sees null because AutocompleteRoot intercepts the prop and replaces it before passing it down (line 96: filter: resolvedFilter).
Suggested fix
Change the truthiness check to an explicit undefined check:
const baseFilter = React.useMemo(() => {
- if (other.filter) {
+ if (other.filter !== undefined) {
return other.filter;
}
return collator.contains;
}, [other.filter, collator]);
This way, filter={null} passes through to AriaCombobox as intended, and filter={undefined} (the default / not provided) still falls back to collator.contains.
Reproduction
// Items are fetched from a server — client-side filtering must be disabled.
<Autocomplete.Root
items={serverResults}
filter={null} // ← expects no client-side filtering
value={searchText}
onValueChange={setSearchText}
itemToStringValue={(item) => item.name}
>
{/* ... */}
</Autocomplete.Root>
Expected: All items in serverResults appear in the dropdown regardless of input text.
Actual: Items are filtered by the default contains filter. If searchText doesn't substring-match any item.name, the dropdown appears empty even though items is non-empty.
Workaround
Pass a function instead of null:
const noFilter = () => true;
<Autocomplete.Root filter={noFilter} ... />
This is truthy, so AutocompleteRoot uses it as the filter function, and it passes all items through.
Environment
Bug report
Problem
Passing
filter={null}to<Autocomplete.Root>does not disable filtering. Instead, the defaultcontainsfilter is silently applied, causing items to be filtered against the input text. This makes some forms of of server-side search unusable with the Autocomplete component when the input text doesn't substring-match the item labels (e.g., searching against multiple fields).I later realized that
filteredItemswas a better approach for the server side filtering use case, but this is still a bug for thefilter.Root cause
In
AutocompleteRoot.tsx, the filter prop is checked with a truthiness test:nullis falsy in JavaScript, soif (other.filter)evaluates tofalse, andbaseFilteris set tocollator.contains(the default case-insensitive string filter). The user'sfilter={null}is silently discarded.By contrast, the underlying
AriaComboboxprimitive handles this correctly:But
AriaComboboxnever seesnullbecauseAutocompleteRootintercepts the prop and replaces it before passing it down (line 96:filter: resolvedFilter).Suggested fix
Change the truthiness check to an explicit
undefinedcheck:const baseFilter = React.useMemo(() => { - if (other.filter) { + if (other.filter !== undefined) { return other.filter; } return collator.contains; }, [other.filter, collator]);This way,
filter={null}passes through toAriaComboboxas intended, andfilter={undefined}(the default / not provided) still falls back tocollator.contains.Reproduction
Expected: All items in
serverResultsappear in the dropdown regardless of input text.Actual: Items are filtered by the default
containsfilter. IfsearchTextdoesn't substring-match anyitem.name, the dropdown appears empty even thoughitemsis non-empty.Workaround
Pass a function instead of
null:This is truthy, so
AutocompleteRootuses it as the filter function, and it passes all items through.Environment
@base-ui/react: 1.2.0