'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 |
