Import
import { Multiselect } from '@contentful/f36-multiselect';
Examples
Basic usage
The Multiselect is a fully controlled form element and expects the selectable items as children via the compound component Multiselect.Option.
Properties are:
For the multiselect itself:
- currentSelection (optional but recommended): an array of the labels of selected options. This will give the user a hint that there are selected items. This is optional
- placeholder (optional): Label of the trigger button without selected elements
- startIcon (optional): Icon on the start of the trigger button
- isLoading: enables showing a loading animation while searching or loading results
Inherited propertys from Popover Component.
- listWidth (optional): auto or full
- listMaxHeight (optional): sets the maximum height of the list drawer, overflow will be scrolled
It also accepts refs for the toggle button, the searchInput and the list.
For the option:
- itemId: identifier for the element, used to link the label with the checkbox
- value: the actual value of the select option
- label: displayed label
- onSelectItem: This function is called when the user selects a option, it needs to be passed to the MultiselectOption
- isChecked (optional): controlls if a element is initially selected
- isDisabled (optional): controlls if a element is changeable
function MultiselectBasicUsageExample() {
  const spaces = [
    'Travel Blog',
    'Finnance Blog',
    'Fitness App',
    'News Website',
    'eCommerce Catalogue',
    'Photo Gallery',
  ];
  
  const [selectedSpaces, setSelectedSpaces] = React.useState([]);
  
  const handleSelectItem = (event) => {
    const { checked, value } = event.target;
    if (checked) {
      setSelectedSpaces((prevState) => [...prevState, value]);
    } else {
      const newSelectedSpaces = selectedSpaces.filter(
        (space) => space !== value,
      );
      setSelectedSpaces(newSelectedSpaces);
    }
  };
  return (
    <Stack flexDirection="column" alignItems="start">
      <Multiselect
        currentSelection={selectedSpaces}
        popoverProps={{ isFullWidth: true }}
      >
        {spaces.map((space) => {
          const val = space.toLowerCase().replace(/\s/g, '-');
          return (
            <Multiselect.Option
              key={`key-${val}}`}
              itemId={`space-${val}}`}
              value={space}
              label={space}
              onSelectItem={handleSelectItem}
              isChecked={selectedSpaces.includes(space)}
            />
          );
        })}
      </Multiselect>
    </Stack>
  );
}
Searchable options
One optional feature of the Multiselect component is to allow filtering the list via a search field.
To make it work, the onSearchValueChange callback function needs to be provided.
To enable searching the following properties have to be set.
- onSearchValueChange: Callbackfunction which enables the search field. This function needs to provide the search /filter algorithm
- searchPlaceholder (optional): placeholder for the search field
- noMatchesMessage (optional): message shown when search result is empty
function MultiselectSearchExample() {
  const spaces = [
    'Travel Blog',
    'Finnance Blog',
    'Fitness App',
    'News Website',
    'eCommerce Catalogue',
    'Photo Gallery',
  ];
  const [selectedItems, setSelectedItems] = React.useState([]);
  const [filteredItems, setFilteredItems] = React.useState(spaces);
  const handleSearchValueChange = (event) => {
    const value = event.target.value;
    const newFilteredItems = spaces.filter((item) =>
      item.toLowerCase().includes(value.toLowerCase()),
    );
    setFilteredItems(newFilteredItems);
  };
  const handleSelectItem = (event) => {
    const { checked, value } = event.target;
    if (checked) {
      setSelectedItems((prevState) => [...prevState, value]);
    } else {
      const newSelectedFruits = selectedItems.filter(
        (fruit) => fruit !== value,
      );
      setSelectedItems(newSelectedFruits);
    }
  };
  return (
    <Stack flexDirection="column" alignItems="start">
      <Multiselect
        searchPlaceholder="Search spaces"
        onSearchValueChange={handleSearchValueChange}
        popoverProps={{ isFullWidth: true }}
        currentSelection={selectedItems}
      >
        {filteredItems.map((item, index) => {
          return (
            <Multiselect.Option
              value={item}
              label={item}
              onSelectItem={handleSelectItem}
              key={`${item}-${index}`}
              itemId={`${item}-${index}`}
              isChecked={selectedItems.includes(item)}
              isDisabled={item === 'eCommerce Catalogue'}
            />
          );
        })}
      </Multiselect>
    </Stack>
  );
}
SelectAll Option
To offer a shortcut for selecting and deselecting all options, you can use the compound component SelectAll. This requires a callback function which needs to contain your implementation for selecting all options.
function MultiselectSelectAllExample() {
  const spaces = React.useMemo(
    () => [
      'Travel Blog',
      'Finnance Blog',
      'Fitness App',
      'News Website',
      'eCommerce Catalogue',
      'Photo Gallery',
    ],
    [],
  );
  
  const [selectedSpaces, setSelectedSpaces] = React.useState([]);
  
  const handleSelectItem = (event) => {
    const { checked, value } = event.target;
    if (checked) {
      setSelectedSpaces((prevState) => [...prevState, value]);
    } else {
      setSelectedSpaces((prevState) =>
        
        prevState.filter((space) => space !== value),
      );
    }
  };
  const toggleAll = (event) => {
    const { checked } = event.target;
    if (checked) {
      setSelectedSpaces(spaces);
    } else {
      setSelectedSpaces([]);
    }
  };
  const areAllSelected = React.useMemo(() => {
    
    return spaces.every((element) => selectedSpaces.includes(element));
  }, [selectedSpaces, spaces]);
  return (
    <Stack flexDirection="column" alignItems="start">
      <Multiselect
        currentSelection={selectedSpaces}
        popoverProps={{ isFullWidth: true }}
      >
        <Multiselect.SelectAll
          onSelectItem={toggleAll}
          isChecked={areAllSelected}
        />
        {spaces.map((space) => {
          const val = space.toLowerCase().replace(/\s/g, '-');
          return (
            <Multiselect.Option
              key={`key-${val}`}
              itemId={`space-${val}`}
              value={space}
              label={space}
              onSelectItem={handleSelectItem}
              isChecked={selectedSpaces.includes(space)}
            />
          );
        })}
      </Multiselect>
    </Stack>
  );
}
Content guidelines
- Multiselect placeholder should be short but descriptive.
- Multiselect options can come from a simple array of strings or more complex objects.
- Do not use the index position of the items in the filtered array for keys or ids, as they are going to change while filtering.
- Use any algorithm you like in order to search and filter. Depending on your implementation you can also generate a new request to your dataset based on the users input.
Accessibility
- When focussing the toggle button, the enter key opens it. The dropdown content automatically will be focussed
- Pressing the space bar toggles the checked state of an option and will trigger the onSelectItem callback function