How to Customize the Material-UI Autocomplete Component

Many React Material-UI components have incredible customizations out-of-the-box, while some are functional but missing nice-to-have options (I’m looking at you, Table-without-a-search-prop).

The Autocomplete component may have the most customization options of any MUI component I’ve seen. Chips, grouping, disabled options, multiselect, custom popup items, fixed options, and more are demoed in the docs.

Link to full JavaScript code is in the Resources section.

***UPDATE for MUI 5: Material-UI moved to a new styling API where styling is applied using the sx prop. If you are using MUI v5, simply insert the styling code directly into the sx prop instead of using makeStyles and classes. I am working on updating my articles, but until I’m finished, read my guide to the MUI sx prop to learn more.

If you are looking for training for Material-UI, check out my review of the best Material-UI course on Udemy, which has 40+ hours of content and a 30-day money back guarantee. The value proposition is simply incredible in this course.

Fetching Remote Data with MUI Autocomplete

(YouTube version of this post here)

Unfortunately, I found that custom styling the Popper and using the renderOption prop were challenging despite the existing examples. Therefore, I created this demo that fetches data from a Star Wars API and populates this custom styled Autocomplete component:

Material-UI Autocomplete Popper styling

Fetching the data required two hooks: useEffect and useState.

const [data, setData] = useState([]);
useEffect(() => {
  fetch("https://swapi-deno.azurewebsites.net/api/starships")
  .then((response) => response.json())
  .then((data) => setData(data));
});

The data is stored in the data state constant and passed as the options prop to the Autocomplete component.

(swapi-deno is a small site that sometimes has downtime…in my Code Sandbox I have the fetch code but also a reduced version of the data locally)

MUI Autocomplete getOptionLabel, renderInput, and renderOption Explained

Below is my code for my customized Autocomplete component. I will explain the three most important (and cryptic) props:

  • getOptionLabel
  • renderInput
  • renderOption
<Autocomplete
id="custom-autocomplete"
options={data}
style={{ width: 350 }}
getOptionLabel={(option) => {
//filter value
return (`${option.name}: ${option.manufacturer}`})
}
renderInput={(params) => {
return (
<TextField
{...params}
variant="outlined"
label="Name: Manufacturer"
/>
);
}}
renderOption={(option) => {
//display value in Popper elements
return <h4>{`${option.name}: ${option.manufacturer}`}</h4>;
}}
PopperComponent={CustomPopper} //required (as far as I can tell) in order to target popper elements for custom styling
/>

getOptionLabel provides the syntax for searching. As it is in my demo, users can search based either on name or manufacturer. However, if I had limited it to getOptionLabel={(option) => (option.name)} then Autocomplete search would only work on name.

renderInput provides the component for users to input search criteria or view selected criteria. This is commonly a TextField component. Even with other customizations such as tags or chips, a TextField is still commonly used here. If you are using a TextField as the renderInput, these two articles will show you how to set Material-UI Autocomplete border and background color.

renderOption controls how the text is rendered in each row of the dropdown (i.e. each Popper <li> element). This prop is not required, however, it provides for significant customization. For example, I changed the elements within each <li> to <h4>renderOption will default to getOptionLabel when it is not otherwise configured.

Styling the Popper Component

I attempted to style the border and background color of the Autocomplete component Popper <li> elements using the common technique below.

const useStyles = makeStyles((theme) =>
  createStyles({
    root: {
      "& .MuiAutocomplete-listbox": {
        "& li:nth-child(even)": { backgroundColor: "#CCC" },
        "& li:nth-child(odd)": { backgroundColor: "#FFF" }
      }
    }
  })
);

However, the popper in the DOM is not a child of the Autocomplete parent element.

Material-UI Autocomplete DOM
Popper DOM

Because of this, simply to style the popper I needed a custom Popper that I could target with the technique above. Here’s the custom Popper I created, with the root class passed to it.

const CustomPopper = function (props) {
const classes = useStyles();
return <Popper {...props} className={classes.root} placement="bottom" />;
};

Now the root class is properly applied and targeting the Listbox.

Let’s dive deeper into the syntax for targeting the Listbox: root: {“& .MuiAutocomplete-listbox”: { } } . This is the class generated on the Listbox DOM <ul> . Using this, I was able to add border styling and target children of the Listbox. The Listbox contains <li> elements; within these elements are whatever elements specified in the renderOption prop (in my case, <h4>). To style every other <li> within Listbox, I targeted “& li:nth-child” .

If you want to style the Autocomplete’s text color, text decoration, font, or control a variety of other styling options, the Popper component is really what you need to target. Also, if you want to set the height of the box containing the Autocomplete options, make sure to set minHeight instead of setting height. The minHeight is set by default and needs to be overridden.

Resources

View Code Sandbox here!

Expand your JavaScript knowledge with these 50 difficult JavaScript questions!

Here’s how to set multiple values programmatically in the Autocomplete component.

Here’s how to style font size, border, and hover for the Autocomplete component.

Docs:

https://material-ui.com/components/autocomplete/

Share this post:

4 thoughts on “How to Customize the Material-UI Autocomplete Component”

  1. Good job with the article Jon. I am trying to keep the autocomplete drop down open after the first choice is picked. Any ideas ? Thanks

    Reply

Leave a Comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.