MUI - Autocomplete
Introduction
This intricate solution of a multi-faceted Autocomplete component was a bigger obstacle than I first expected, therefore I decided to document it and share it online for further documentation.
Code
import React from "react";
import { Autocomplete, TextField, Box, Stack, Chip } from "@mui/material";
import TransitEnterexitIcon from "@mui/icons-material/TransitEnterexit";
import CloseIcon from "@mui/icons-material/Close";
const apiTags = [
{ title: "The Shawshank Redemption", year: 1994, group: "Scenes" },
{ title: "The Godfather", year: 1972, group: "Scenes" },
{ title: "The Godfather: Part II", year: 1974, group: "Exlusives" },
{ title: "The Dark Knight", year: 2008, group: "Exlusives" }
];
const AutoCompleteField = () => {
const [tags, setTags] = React.useState([]);
const handleChangeAutoComplete = (event, value) => {
const newTag = (() => {
const tempTag = value.at(-1);
if (typeof tempTag === "string") {
return tempTag.trim();
}
return undefined;
})();
const oldTags = value.slice(0, newTag === undefined ? undefined : -1);
if (newTag === undefined) {
return setTags(oldTags);
}
const obj = {
title: newTag,
year: 1990,
group: "Recently added"
};
return setTags([...oldTags, obj]);
};
return (
<Autocomplete
disablePortal
renderGroup={(params) => (
<Box key={params.group} sx={{ padding: "10px 20px" }}>
<p>{params.group}</p>
<Stack direction="row" flexWrap="wrap" gap="8px">
{React.Children.map(params.children, (element, index) => (
<Box key={index} sx={{ border: "1px solid grey" }}>
{element}
</Box>
))}
</Stack>
</Box>
)}
multiple
fullWidth
options={apiTags}
groupBy={(tag) => tag.group}
value={tags}
freeSolo
onChange={handleChangeAutoComplete}
getOptionLabel={(option) => {
if (typeof option === "string") {
return option;
}
return option.title;
}}
renderInput={(params) => (
<TextField
{...params}
name="tags"
placeholder="Start adding tags here"
size="small"
margin="none"
variant="outlined"
fullWidth
required
InputProps={{
...params.InputProps,
endAdornment: <TransitEnterexitIcon />,
onKeyDown: (e) => {
if (e.key === "Enter") {
e.preventDefault();
}
},
style: {
color: "grey",
fontWeight: "500",
fontSize: "16px"
}
}}
/>
)}
renderTags={(value, getTagProps) =>
value?.map((option, index) => (
<Chip
key={index}
deleteIcon={
<CloseIcon
sx={{
fill: "blue",
width: "16px"
}}
/>
}
label={option.title}
{...getTagProps({ index })}
/>
))
}
/>
);
};
export default AutoCompleteField;Breakdown
Most of the explanation of the parameters passed down to the component can be found in MUI’s documentation. But, let’s see closer how to set up this component to accept pre-defined tags (given to the user in a dropdown) and tags created by the user on the fly.