AutocompleteInput

The AutocompleteInput module provides you input components that include a dropdown for autocomplete suggestions. There are two components exported from the module, one for a single-selection field and another for multi-selection.

Usage

The components are controlled components. That means that you are responsible to tell the components which items are currently selected and which are visible in the dropdown.

An item in terms of this component is an object that contains at least two properties: An id property that is unique among all the items that are selected or visible and a label property, which will be shown when the item is displayed.

You are of course allowed to pass objects as items that contain more than the required properties. If you use TypeScript, you can pass the type definition of your items as generic argument to the component:

const props = {/* Define your props */};
type CustomItem = { id: string; label: string; foo: number };
const Foo = () =>
  <AutocompleteInput.SingleSelect<CustomItem> {...props} />;

Both single- and multi-select have a set of common props, which are defined in the following table:

Property nameTypeRequiredValuesDefault
renderItemRenderItem--
visibleItemsVisibleItemsGetter--
onInputValueChangeInputValueChangeHandler--
idstring--
namestring--
placeholderstring--
statestringsee the states of the InputBox component-

Here are the complete type definitions:

type RenderItem = (item: Item) => React.ReactNode;

type VisibleItemsGetter = (
  downshift: ControllerStateAndHelpers<Item>,
) => Item[];

type InputValueChangeHandler = (
  inputValue: string,
  downshift: ControllerStateAndHelpers<Item>,
) => void;

The ControllerStateAndHelpers is taken from downshift. Item is the type of the items used when rendering the component.

The props id, name, state and placeholder will be passed to the InputBox which is used under the hood to render the styled input field.

To control the items shown in the dropdown below the input field you have to pass a function via the visibleItems prop. To allow you to base the visible items on the current state of the component, we pass all the internal downshift-state as argument to this function. You can for example use the current value of the input element like this:

<AutocompleteInput.SingleSelect
  visibleItems={(downshift) => {
    const currentInput = downshift.inputValue;
    // Decide on which items to show...
  }}
  {...otherProps}
/>

To actually render the individual items you have to pass a renderItem prop. This function will be called for each individual item. You have to return a ReactNode that will be inserted in the list of visible item.

To listen on change events for the input field you can pass a handler via the onInputValueChange prop. This function will be called with the new value of the input as first argument and with the current downshift state as the second argument. (Note that the event handler is called before the downshift state is update. That means downshift.inputValue still contains the old value of the input element.)

Single-select

The following props are specific to the single-select component:

Property nameTypeRequiredValuesDefault
onSelectSelectHandler--
selectedItem`Itemnull`--
clearInputValueOnSelectionboolean--

Here is the complete type definition for the onSelect prop:

type SelectHandler = (
  selectedItem: Item | null,
  downshift: ControllerStateAndHelpers<Item>,
) => void;

Multi-select

The following props are specific to the single-select component:

Property nameTypeRequiredValuesDefault
onSelectionChangeSelectHandler--
selectedItemsItem[]--

Here is the complete type definition for the onSelectionChange prop:

type SelectHandler = (
  selectedItems: Item[],
  downshift: ControllerStateAndHelpers<Item>,
) => void;

Example

Single-select

type Item = { id: string; label: string };
const items = [
  { id: "apple", label: "Apple" },
  { id: "banana", label: "Banana" },
  { id: "coconut", label: "Coconut" },
];
const SingleSelectExample: React.FC = () => {
  const [selectedItem, setSelectedItem] = useState<Item | null>(null);
  return (
    <Spacings.Stack>
      <label htmlFor="single-select">
        <Text>Select a fruit</Text>
      </label>
      <AutocompleteInput.SingleSelect
        clearInputValueOnSelection
        id="single-select"
        onSelect={(item) => {
          setSelectedItem(item);
        }}
        selectedItem={selectedItem}
        visibleItems={(downshift) =>
          downshift.inputValue === ""
            ? items
            : items.filter((item) =>
                item.label
                  .toLowerCase()
                  .includes((downshift.inputValue || "").toLowerCase()),
              )
        }
      />
    </Spacings.Stack>
  );
};

Multi-select

type Item = { id: string; label: string };
const items = [
  { id: "apple", label: "Apple" },
  { id: "banana", label: "Banana" },
  { id: "coconut", label: "Coconut" },
];
const MultiSelectExample: React.FC = () => {
  const [selectedItems, setSelectedItems] = useState<Item[]>([]);
  return (
    <Spacings.Stack>
      <label htmlFor="multi-select">
        <Text>Select multiple fruits</Text>
      </label>
      <AutocompleteInput.MultiSelect
        id="multi-select"
        onSelectionChange={(itemList) => {
          setSelectedItems(itemList);
        }}
        selectedItems={selectedItems}
        visibleItems={(downshift) =>
          downshift.inputValue === ""
            ? items
            : items.filter((item) =>
                item.label
                  .toLowerCase()
                  .includes((downshift.inputValue || "").toLowerCase()),
              )
        }
      />
    </Spacings.Stack>
  );
};