Search code examples
reactjsmaterial-ui

MUI Select with Chips, and Chips with Delete button


So, I'm trying to follow the example code on MUI Select with Chips:

This is what I changed to their code:

import * as React from 'react';
import { useTheme } from '@mui/material/styles';
import Box from '@mui/material/Box';
import OutlinedInput from '@mui/material/OutlinedInput';
import InputLabel from '@mui/material/InputLabel';
import MenuItem from '@mui/material/MenuItem';
import FormControl from '@mui/material/FormControl';
import Select from '@mui/material/Select';
import Chip from '@mui/material/Chip';

const ITEM_HEIGHT = 48;
const ITEM_PADDING_TOP = 8;
const MenuProps = {
  PaperProps: {
    style: {
      maxHeight: ITEM_HEIGHT * 4.5 + ITEM_PADDING_TOP,
      width: 250,
    },
  },
};

const names = [
  'Oliver Hansen',
  'Van Henry',
  'April Tucker',
  'Ralph Hubbard',
  'Omar Alexander',
  'Carlos Abbott',
  'Miriam Wagner',
  'Bradley Wilkerson',
  'Virginia Andrews',
  'Kelly Snyder',
];

function getStyles(name, personName, theme) {
  return {
    fontWeight: personName.includes(name)
      ? theme.typography.fontWeightMedium
      : theme.typography.fontWeightRegular,
  };
}

export default function MultipleSelectChip() {
  const theme = useTheme();
  const [personName, setPersonName] = React.useState([]);

  const handleChange = (event) => {
    const {
      target: { value },
    } = event;
    setPersonName(
      // On autofill we get a stringified value.
      typeof value === 'string' ? value.split(',') : value,
    );
  };

   const handleDelete = (nameToDelete) => {
    setPersonName((names) =>
      names.filter((name) => name !== nameToDelete)
    );
  };

  return (
    <div>
      <FormControl sx={{ m: 1, width: 300 }}>
        <InputLabel id="demo-multiple-chip-label">Chip</InputLabel>
        <Select
          labelId="demo-multiple-chip-label"
          id="demo-multiple-chip"
          multiple
          value={personName}
          onChange={handleChange}
          input={<OutlinedInput id="select-multiple-chip" label="Chip" />}
          renderValue={(selected) => (
            <Box sx={{ display: 'flex', flexWrap: 'wrap', gap: 0.5 }}>
              {selected.map((value) => (
                <Chip 
                  key={value} 
                  label={value} 
                  onDelete={(event) => {
                            event.stopPropagation(); // Prevent the select dropdown from opening
                            handleDelete(value);
                          }}
                />
              ))}
            </Box>
          )}
          MenuProps={MenuProps}
        >
          {names.map((name) => (
            <MenuItem
              key={name}
              value={name}
              style={getStyles(name, personName, theme)}
            >
              {name}
            </MenuItem>
          ))}
        </Select>
      </FormControl>
    </div>
  );
}

It was after I checked with Codium that it suggested adding this part: event.stopPropagation();

But it still didn't work, whenever I click on the (x) button on the Chip, it opens the list, instead of deleting the Chip.

Does anyone have any idea?

This is the code in sandbox (the (X) gives the mouse hand icon, but opens the list).


Solution

  • Providing a higher z-index to the Chip element will work.

    <Chip
      sx={{ zIndex: 9999 }}
      key={value}
      label={value}
      onDelete={(event) => {
        console.log("Deleting...");
        event.stopPropagation();
        handleDelete(value);
      }}
    />
    

    Check this working demo.

    That said, for multiselect UI I think you can use the Material Autocomplete component as it has the built-in functionality to handle deleting the selected items.