hc-oss / react-multi-select-component

Lightweight (~5KB gzipped) multiple selection dropdown component
https://codesandbox.io/s/react-multi-select-example-uqtgs
MIT License
386 stars 89 forks source link

Feature Request: Can we get a option to delete individual selected items #349

Closed ramesh-joshi closed 3 years ago

ramesh-joshi commented 3 years ago

Hi Team,

Can we get a option to show the delete icon for individual selected items something like this, (X icon inside the red circle )

image

Thanks, Joshi

harshzalavadiya commented 3 years ago

@ramesh-joshi this is easily possible by using custom renderer like below, but the best option will be to go with react-select

https://user-images.githubusercontent.com/5774849/113266774-435feb80-92f3-11eb-8c6f-0e16bf0c8145.mp4

import React, { useState } from "react";
import MultiSelect from "react-multi-select-component";
import "./styles.css";

export default function App() {
  const options = [
    { label: "Grapes 🍇", value: "grapes" },
    { label: "Mango 🥭", value: "mango" },
    { label: "Strawberry 🍓", value: "strawberry" }
  ];

  const [selected, setSelected] = useState([]);

  // removes passed value from selected array
+ const deleteItem = (value) => setSelected(selected.filter((item) => item.value !== value))

  // custom value render
+  const customValueRenderer = (selected, _options) => (
+    <>
+     {selected.map((item) => (
+       <span key={item.value}>
+         {item.label}
+         <button onClick={() => deleteItem(item.value)}>[X]</button>
+       </span>
+     ))}
+   </>
+ );

  return (
    <MultiSelect
      options={options}
      value={selected}
      onChange={setSelected}
      labelledBy={"Select"}
+     valueRenderer={customValueRenderer}
    />
  );
}
ramesh-joshi commented 3 years ago

Hi @harshzalavadiya,

Thank you so much for this.

Yeah, I did the same way and its working fine but only one problem is there, when we click the delete item icon the bottom menu items pops-up alternatively. if we can fix this then it will be prefect package.

This package is very light weight and has most of the features so not planning to use another (react-select) package.

Thank you

harshzalavadiya commented 3 years ago

@ramesh-joshi yes this can be done making changes as below

// removes passed value from selected array
- const deleteItem = (value) => {
+ const deleteItem = (e, value) => {
    // Prevent event bubbling so dropdown won't close automatically
+   e.stopPropagation();
    setSelected(selected.filter((item) => item.value !== value));
  };

  // custom value render
  const customValueRenderer = (selected, _options) => (
    <>
      {selected.map((item) => (
        <span key={item.value}>
          {item.label}
          {/*
            - we use span here instead of button so on clicking it won't transfer focus
            - for accessiblity aria attributes can be used
          */}
-         <button onClick={() => deleteItem(item.value)}>✕</button>
+         <span onClick={(e) => deleteItem(e, item.value)}>✕</span>
        </span>
      ))}
    </>
  );