Muhi Logo Text
AboutBlogWork With Me

How to Create a Multiselect Component with Material UI (MUI)

Learn how to create and customize a Multiselect component with Material UI and React

Last updated on March 11, 2023

react
mui
MUI Multiselect

Multiselect in Material UI is an extended feature to the regular select or dropdown menu that enables users to select multiple values within the same input field.

MUI provides a couple of convenient options to get a feature-rich multiselect component included in our project.

In this tutorial, we’ll learn how to create a multiselect component using Select and Autocomplete with a customized menu list and removable tags/chips as values.

Here is what the final code will look like:

If this is your first time working with MUI, please follow the installation instructions from the official documentation to get started.

Using Select Component

Multiselect at a basic level is similar to the regular Select component syntax except for adding multiple prop to enable multiple selections.

import React, { useState } from "react";
import {
  OutlinedInput,
  InputLabel,
  MenuItem,
  Select,
  FormControl
} from "@mui/material";

const names = [
  "Humaira Sims",
  "Santiago Solis",
  "Dawid Floyd",
  "Mateo Barlow",
  "Samia Navarro",
  "Kaden Fields",
  "Genevieve Watkins",
  "Mariah Hickman",
  "Rocco Richardson",
  "Harris Glenn"
];

export default function MultiSelect() {
  const [selectedNames, setSelectedNames] = useState([]);

  return (
    <FormControl sx={{ m: 1, width: 500 }}>
      <InputLabel>Multiple Select</InputLabel>
      <Select
        multiple
        value={selectedNames}
        onChange={(e) => setSelectedNames(e.target.value)}
        input={<OutlinedInput label="Multiple Select" />}
      >
        {names.map((name) => (
          <MenuItem key={name} value={name}>
            {name}
          </MenuItem>
        ))}
      </Select>
    </FormControl>
  );
}

Customize Selected Values

To customize the selected values, we need to use the renderValue prop and loop through the selected values to insert them into the component of our choice. We use Chip in this example to make it look like tags.

import React, { useState } from "react";
import {
  OutlinedInput,
  InputLabel,
  MenuItem,
  Select,
  FormControl,
  Stack,
  Chip
} from "@mui/material";

const names = [
  "Humaira Sims",
  "Santiago Solis",
  "Dawid Floyd",
  "Mateo Barlow",
  "Samia Navarro",
  "Kaden Fields",
  "Genevieve Watkins",
  "Mariah Hickman",
  "Rocco Richardson",
  "Harris Glenn"
];

export default function MultiSelect() {
  const [selectedNames, setSelectedNames] = useState([]);

  return (
    <FormControl sx={{ m: 1, width: 500 }}>
      <InputLabel>Multiple Select</InputLabel>
      <Select
        multiple
        value={selectedNames}
        onChange={(e) => setSelectedNames(e.target.value)}
        input={<OutlinedInput label="Multiple Select" />}
        renderValue={(selected) => (
          <Stack gap={1} direction="row" flexWrap="wrap">
            {selected.map((value) => (
              <Chip key={value} label={value} />
            ))}
          </Stack>
        )}
      >
        {names.map((name) => (
          <MenuItem key={name} value={name}>
            {name}
          </MenuItem>
        ))}
      </Select>
    </FormControl>
  );
}

We also added a Stack wrapper to align tags horizontally.

Remove Selected Values

To delete selected values, we need to define an onDelete handler and add a deleteIcon to display on the Chip component.

import React, { useState } from "react";
import {
  OutlinedInput,
  InputLabel,
  MenuItem,
  Select,
  FormControl,
  Stack,
  Chip
} from "@mui/material";
import CancelIcon from "@mui/icons-material/Cancel";
const names = [
  "Humaira Sims",
  "Santiago Solis",
  "Dawid Floyd",
  "Mateo Barlow",
  "Samia Navarro",
  "Kaden Fields",
  "Genevieve Watkins",
  "Mariah Hickman",
  "Rocco Richardson",
  "Harris Glenn"
];
export default function MultiSelect() {
  const [selectedNames, setSelectedNames] = useState([]);
  return (
    <FormControl sx={{ m: 1, width: 500 }}>
      <InputLabel>Multiple Select</InputLabel>
      <Select
        multiple
        value={selectedNames}
        onChange={(e) => setSelectedNames(e.target.value)}
        input={<OutlinedInput label="Multiple Select" />}
        renderValue={(selected) => (
          <Stack gap={1} direction="row" flexWrap="wrap">
            {selected.map((value) => (
              <Chip
                key={value}
                label={value}
                onDelete={() =>
                  setSelectedNames(
                    selectedNames.filter((item) => item !== value)
                  )
                }
                deleteIcon={
                  <CancelIcon
                    onMouseDown={(event) => event.stopPropagation()}
                  />
                }
              />
            ))}
          </Stack>
        )}
      >
        {names.map((name) => (
          <MenuItem key={name} value={name}>
            {name}
          </MenuItem>
        ))}
      </Select>
    </FormControl>
  );
}

Notice that we added an onMouseDown handler to stop the Select from opening the list as the user clicks the “Cancel” icon. It’s a small required hack because of some limitations on the Select component.

Customize Menu Item

MenuItem is the component used to display all available options, and currently, any selected value has a light background color. Below, we will enhance it by adding a checkmark icon to make selections more visible.

import React, { useState } from "react";
import {
  OutlinedInput,
  InputLabel,
  MenuItem,
  Select,
  FormControl,
  Stack,
  Chip
} from "@mui/material";
import CancelIcon from "@mui/icons-material/Cancel";
import CheckIcon from "@mui/icons-material/Check";

const names = [
  "Humaira Sims",
  "Santiago Solis",
  "Dawid Floyd",
  "Mateo Barlow",
  "Samia Navarro",
  "Kaden Fields",
  "Genevieve Watkins",
  "Mariah Hickman",
  "Rocco Richardson",
  "Harris Glenn"
];

export default function MultiSelect() {
  const [selectedNames, setSelectedNames] = useState([]);

  return (
    <FormControl sx={{ m: 1, width: 500 }}>
      <InputLabel>Multiple Select</InputLabel>
      <Select
        multiple
        value={selectedNames}
        onChange={(e) => setSelectedNames(e.target.value)}
        input={<OutlinedInput label="Multiple Select" />}
        renderValue={(selected) => (
          <Stack gap={1} direction="row" flexWrap="wrap">
            {selected.map((value) => (
              <Chip
                key={value}
                label={value}
                onDelete={() =>
                  setSelectedNames(
                    selectedNames.filter((item) => item !== value)
                  )
                }
                deleteIcon={
                  <CancelIcon
                    onMouseDown={(event) => event.stopPropagation()}
                  />
                }
              />
            ))}
          </Stack>
        )}
      >
        {names.map((name) => (
          <MenuItem
            key={name}
            value={name}
            sx={{ justifyContent: "space-between" }}
          >
            {name}
            {selectedNames.includes(name) ? <CheckIcon color="info" /> : null}
          </MenuItem>
        ))}
      </Select>
    </FormControl>
  );
}

Using Autocomplete Component

Autocomplete is similar to the Select component in terms of providing a list of options with a multiselect feature. However, it’s a regular text input enhanced by a panel of suggested options and can be an excellent alternative for more advanced features.

For example, the basic usage below will provide us with all the features we customized in the previous section and more!

import React from "react";
import { TextField, Autocomplete } from "@mui/material";

const names = [
  "Humaira Sims",
  "Santiago Solis",
  "Dawid Floyd",
  "Mateo Barlow",
  "Samia Navarro",
  "Kaden Fields",
  "Genevieve Watkins",
  "Mariah Hickman",
  "Rocco Richardson",
  "Harris Glenn"
];

export default function MultiSelect() {
  return (
    <Autocomplete
      sx={{ m: 1, width: 500 }}
      multiple
      options={names}
      getOptionLabel={(option) => option}
      disableCloseOnSelect
      renderInput={(params) => (
        <TextField
          {...params}
          variant="outlined"
          label="Multiple Autocomplete"
          placeholder="Multiple Autocomplete"
        />
      )}
    />
  );
}

As we can see above, the code is shorter than the Select component, and we get the following functionalities out of the box:

  • Autocomplete on user input.
  • Chip component for selected values by default.
  • Multiselect with adding and removing all values option.

Additionally, we are no longer required to add useState to the manage list. Instead, we can use the onChange prop to detect any value changes in the list.

For reference, this link has the official Autocomplete component API from Material UI

The only thing we are missing is adding a check mark on selected values. We can use similar code from the previous section using the MenuItem component, but we no longer need to loop through the list. Instead, Autocomplete provides a renderOption prop fired on every item.

import React from "react";
import { TextField, Autocomplete, MenuItem } from "@mui/material";
import CheckIcon from "@mui/icons-material/Check";

const names = [
  "Humaira Sims",
  "Santiago Solis",
  "Dawid Floyd",
  "Mateo Barlow",
  "Samia Navarro",
  "Kaden Fields",
  "Genevieve Watkins",
  "Mariah Hickman",
  "Rocco Richardson",
  "Harris Glenn"
];

export default function MultiSelect() {
  return (
    <Autocomplete
      sx={{ m: 1, width: 500 }}
      multiple
      options={names}
      getOptionLabel={(option) => option}
      disableCloseOnSelect
      renderInput={(params) => (
        <TextField
          {...params}
          variant="outlined"
          label="Multiple Autocomplete"
          placeholder="Multiple Autocomplete"
        />
      )}
      renderOption={(props, option, { selected }) => (
        <MenuItem
          {...props}
          key={option}
          value={option}
          sx={{ justifyContent: "space-between" }}
        >
          {option}
          {selected ? <CheckIcon color="info" /> : null}
        </MenuItem>
      )}
    />
  );
}

Summary

Both components are great for implementing a multiselect feature. However, the Select component is sufficient if we are looking for a simple solution without adding, removing, and auto-completing. Otherwise, Autocomplete is recommended for more advanced features.

Bye for now 👋

If you enjoyed this post, I regularly share similar content on Twitter. Follow me @muhimasri to stay up to date, or feel free to message me on Twitter if you have any questions or comments. I'm always open to discussing the topics I write about!

Recommended Reading

Learn how to create encapsulated and reusable Fieldset component with Material UI (MUI) and React.

react
mui

Discussion

Upskill Your Frontend Development Techniques 🌟

Subscribe to stay up-to-date and receive quality front-end development tutorials straight to your inbox!

No spam, sales, or ads. Unsubscribe anytime you wish.

© 2024, Muhi Masri