Autocomplete
The Autocomplete component is a text input enhanced by a panel of suggested options.
Introduction
The autocomplete component is an enhanced text input that shows a list of suggested options as users type and lets them select an option from the list. It implements the WAI-ARIA Combobox pattern, and is typically used to assist users in completing form inputs or search queries faster.
Usage
After installation, you can start building with this hook as follows:
import useAutocomplete from '@mui/base/useAutocomplete';
export default function App() {
const {
getRootProps,
getInputProps,
getListboxProps,
getOptionProps,
groupedOptions,
} = useAutocomplete({
options: [
{ label: 'The Dark Knight', year: 2008 },
{ label: '12 Angry Men', year: 1957 },
{ label: "Schindler's List", year: 1993 },
],
getOptionLabel: (option) => option.label,
});
return (
<React.Fragment>
<div {...getRootProps()}>
<input {...getInputProps()} />
</div>
{groupedOptions.length > 0 && (
<ul {...getListboxProps()}>
{groupedOptions.map((option, index) => (
<li {...getOptionProps({ option, index })}>{option.label}</li>
))}
</ul>
)}
</React.Fragment>
);
}
Basics
The useAutocomplete hook requires a list of options
to be displayed when the textbox receives focus. The value must be chosen from a predefined set of values.
The following demo shows how to create a simple combobox, apply some styling, and write the selected value to a state variable using the onChange
prop:
Customization
Rendering options
By default, the options
prop accepts an array of string
s or { label: string }
:
const options = [
{ label: 'The Godfather', id: 1 },
{ label: 'Pulp Fiction', id: 2 },
];
// or
const options = ['The Godfather', 'Pulp Fiction'];
If you need to use a different structure for options, you must provide a function to the getOptionLabel
prop that resolves each option to a unique value.
const options = [
{ issuer: 'Bank of America', brand: 'Visa', last4: '1234' },
{ issuer: 'Bank of America', brand: 'MasterCard', last4: '5678' },
{ issuer: 'Barclays', brand: 'Visa', last4: '4698' },
// ...
];
const {
getRootProps,
// etc
} = useAutocomplete({
getOptionLabel: (option) => option.last4,
});
Controlled states
The useAutocomplete hook has two states that can be controlled:
- the "value" state with the
value
/onChange
props combination. This state represents the value selected by the user, for instance when pressing Enter. - the "input value" state with the
inputValue
/onInputChange
props combination. This state represents the value displayed in the textbox.
These two states are isolated, and should be controlled independently.
value: Firefox
inputValue:
Using a portal
React Portals can be used to render the listbox outside of the DOM hierarchy, making it easier to allow it to "float" above adjacent elements.
Base UI provides a <Popper />
component built around React's createPortal()
for exactly this purpose, and additionally helps you manage keyboard focus as it moves in and out of the portal.
To render the listbox in Base UI's Popper, the ref
s must be merged as follows:
import useAutocomplete from '@mui/base/useAutocomplete';
import Popper from '@mui/base/Popper';
import { unstable_useForkRef as useForkRef } from '@mui/utils';
export default function App(props) {
const {
getRootProps,
getInputProps,
getListboxProps,
getOptionProps,
popupOpen,
anchorEl,
setAnchorEl,
groupedOptions,
} = useAutocomplete(props);
const rootRef = useForkRef(ref, setAnchorEl);
return (
<React.Fragment>
<div {...getRootProps()} ref={rootRef}>
<input {...getInputProps()} />
</div>
{anchorEl && (
<Popper open={popupOpen} anchorEl={anchorEl}>
{groupedOptions.length > 0 && (
<ul {...getListboxProps()}>
{groupedOptions.map((option, index) => (
<li {...getOptionProps({ option, index })}>{option.label}</li>
))}
</ul>
)}
</Popper>
)}
</React.Fragment>
);
}
Here's a complete demo that renders the listbox inside a Popper: