'Select All / Unselect All option in react-select

Is it possible to have the 'Select All / Unselect All' option in react-select? Is this something that is built in, or I have to do it my self?



Solution 1:[1]

At the company where I work we've made a wrapper around react-select with some additional features and styling. One of the features is Select/Unselect All.

Here is a link to page that demoes the component:

https://topia.design/components/multi-select/

Here is the approach that I've used to implement Select/Unselect All:

https://codesandbox.io/s/distracted-panini-8458i?file=/src/MultiSelect.js

import React, { useRef } from "react";
import ReactSelect from "react-select";

export const MultiSelect = props => {
  // isOptionSelected sees previous props.value after onChange
  const valueRef = useRef(props.value);
  valueRef.current = props.value;

  const selectAllOption = {
    value: "<SELECT_ALL>",
    label: "All Items"
  };

  const isSelectAllSelected = () =>
    valueRef.current.length === props.options.length;

  const isOptionSelected = option =>
    valueRef.current.some(({ value }) => value === option.value) ||
    isSelectAllSelected();

  const getOptions = () => [selectAllOption, ...props.options];

  const getValue = () =>
    isSelectAllSelected() ? [selectAllOption] : props.value;

  const onChange = (newValue, actionMeta) => {
    const { action, option, removedValue } = actionMeta;

    if (action === "select-option" && option.value === selectAllOption.value) {
      props.onChange(props.options, actionMeta);
    } else if (
      (action === "deselect-option" &&
        option.value === selectAllOption.value) ||
      (action === "remove-value" &&
        removedValue.value === selectAllOption.value)
    ) {
      props.onChange([], actionMeta);
    } else if (
      actionMeta.action === "deselect-option" &&
      isSelectAllSelected()
    ) {
      props.onChange(
        props.options.filter(({ value }) => value !== option.value),
        actionMeta
      );
    } else {
      props.onChange(newValue || [], actionMeta);
    }
  };

  return (
    <ReactSelect
      isOptionSelected={isOptionSelected}
      options={getOptions()}
      value={getValue()}
      onChange={onChange}
      hideSelectedOptions={false}
      closeMenuOnSelect={false}
      isMulti
    />
  );
};

Solution 2:[2]

I inspired from Alex's method, but i changed some section of his code. There is a example i prepared, if you still need, you can check.

And also I made another example for the case that there is too much data, i solved performance problem with react-window and i changed input value if user select more than 5 items.

Solution 3:[3]

Solution for [email protected] (achieves "select all" option gracefully") (remove TypeScript parts to run in pure jS)

const MultiSelect: React.FC<MultiSelectProps> = ({
  options,
  defaultValue,
  onChange,
}) => {
  const selectAllOption = { label: 'select all', value: '*' };

  const initialVisibleOptions =
    options.length === defaultValue?.length
      ? options
      : [...options, selectAllOption];

  const [availableOptions, setAvailableOptions] = useState<Option[]>(
    initialVisibleOptions,
  );

  const [selectedValues, setSelectedValues] = useState<readonly Option[]>(
    defaultValue,
  );

  const relayOnChange = (newSelectedOptions: readonly Option[]) => {
    const selectAllIsSelected = !!newSelectedOptions.find(
      o => o.value === selectAllOption.value,
    );

    const newComponentState = selectAllIsSelected
      ? {
          selectedValues: options,
          availableOptions: [],
        }
      : {
          selectedValues: newSelectedOptions,
          availableOptions: initialVisibleOptions,
        };

    setSelectedValues(newComponentState.selectedValues);
    setAvailableOptions(newComponentState.availableOptions);
    onChange(newComponentState.selectedValues);
  };

  return (
    <Select
      isMulti
      options={availableOptions}
      value={selectedValues}
      defaultValue={selectedValues}
      onChange={relayOnChange}
    />
  );
};

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2
Solution 3 Tomasz Szawara