---
name: Typeahead
menu: Patterns
parent: Modules
route: /patterns/typeahead
---

# Typeahead

Typeahead component encapsulates autocomplete search functionality and provides users with a list of suggested options.

```specimen-react
<DocStateProvider initialState={{
  items: [],
  allItems: [
      { value: '40 Hanbury Street', id: '1' },
      { value: '42 Hanbury Street', id: '2' },
      { value: '44 Hanbury Street', id: '3' },
      { value: '46 Hanbury Street', id: '4' },
      { value: '48 Hanbury Street', id: '5' },
      { value: '50 Hanbury Street', id: '6' },
      { value: '52 Hanbury Street', id: '7' },
      { value: '155 Bishopsgate', id: '8' },
  ] }}>
  {({ state, setState }) => {
    return (
      <Typeahead
        label="Address"
        placeholder="Start typing your address"
        searchDescription={<p>Keep typing to find your address</p>}
        loading={false}
        notFoundItem={{
          value: 'Can\'t find my address',
          id: 'cant-find-my-address',
          node: <strong>Can't find my address</strong>
        }}
        handleStateChange={(options, getStateAndHelpers) => {
          const { inputValue, selectedItem } = options;
          if (selectedItem) {
            alert(`You selected ${selectedItem.value}`);
          }

          if (!inputValue) {
            return;
          }

          const filteredItems = state.allItems.filter(item =>
            new RegExp(inputValue, 'i').test(item.value));

          const highlight = (items, inputValue) => {
            const getHighlightedText = (item, inputValue) => {
              const inputValueRegex = new RegExp(inputValue, 'i');
              const startIndex = item.value.search(inputValueRegex);
              const endIndex = inputValue.length + startIndex;
              return (
                <span>
                  {item.value.substring(0, startIndex)}
                  <strong>{item.value.substring(startIndex, endIndex)}</strong>
                  {item.value.substring(endIndex)}
                </span>
              );
            }

            return items.map(item => {
              return {
                value: item.value,
                id: item.id,
                node: getHighlightedText(item, inputValue),
              };
            });
          }

          const items = highlight(filteredItems, inputValue);
          setState({ items });
        }}
        items={state.items}/>
    )
  }}
</DocStateProvider>
```

Try typing "Hanbury" in the above text input field and select an item from the suggested list.

## Configurations

### Open by default

Set the [`isOpen`](#isopen) property to be true by default.
This configuration will also cause the component to push content down instead of overlapping by default.

```specimen-react
  <Typeahead
    label="Address"
    placeholder="Start typing your address"
    searchDescription={<p>Keep typing to find your address</p>}
    loading={false}
    defaultIsOpen={true}
    handleStateChange={() => {}}
    notFoundItem={{
      value: 'Can\'t find my address',
      id: 'cant-find-my-address',
      node: <strong>Can't find my address</strong>
    }}
    items={[
      { value: '40 Hanbury Street', id: '1', node: '40 Hanbury Street' },
    ]}
    isOpen={true}
    />
```

### Initial selected item

Set a selected item for when the component is initialised.

```specimen-react
  <Typeahead
    label="Address"
    placeholder="Start typing your address"
    searchDescription={<p>Keep typing to find your address</p>}
    loading={false}
    initialSelectedItem={{
      value: '40 Hanbury Street',
      id: '1',
      node: <strong>40 Hanbury Street</strong>
    }}
    notFoundItem={{
      value: 'Can\'t find my address',
      id: 'cant-find-my-address',
      node: <strong>Can't find my address</strong>
    }}
    handleStateChange={() => {}}
    items={[
      { value: '40 Hanbury Street', id: '1', node: '40 Hanbury Street' },
  ] }/>
```

### Loading

Display a loading state to indicate that items are being fetched.

```specimen-react
  <Typeahead
    label="Address"
    placeholder="Start typing your address"
    searchDescription={<p>Keep typing to find your address</p>}
    loading={true}
    defaultIsOpen={true}
    notFoundItem={{
      value: 'Can\'t find my address',
      id: 'cant-find-my-address',
      node: <strong>Can't find my address</strong>
    }}
    handleStateChange={() => {}}
    isOpen={true}
    items={[]}/>
```

## Implementation

### Props

#### `label`

A label for the text input element.

#### `placeholder`

A placeholder for the text input element.

#### `searchDescription`

A guidance message to display above the [`items`](#items) list.

#### `loading`

Displays a loading spinner inside the [`searchDescription`](#searchdescription) when set to `true`.

#### `notFoundItem`

An `Item` that allows the user to select that they have not found an item they are searching for.

#### `handleStateChange`

Receives [`TypeaheadOptions`](#typeaheadoptions)

Consumers should use this function to filter the items list by the [`inputValue`](#inputvalue). Another suggested functionality would be to highlight the text in the [`items`](#items) that matches the [`inputValue`](#inputvalue).

A working example of this function has been provided in the demo.

For reading updates in the selected item, use [`onItemSelection`](#onitemselection).

#### `onInputValueChange`

Consumers can use this function to receive the [`inputValue`](#inputvalue). It is recommened when using the `inputValue` as a controlled prop.

#### `items`

The list of selectable items in the Typeahead.

#### `isOpen`

Whether the menu is open or closed.

#### `defaultIsOpen`

Set the [`isOpen`](#isopen) value anytime the component is reset, when a selection is cleared, or an item is selected.

#### `initialInputValue`

Set an initial value when the Typeahead is initialised.

#### `inputValue`

The value the text input should have.

The [`selectedItem`](#selecteditem) and [`initialSelectedItem`](#initialselecteditem) props take precendence over `inputValue`.

#### `initialSelectedItem`

Pass an item or an array of items that should be selected when the Typeahead is initialised.

#### `selectedItem`

The currently selected item.

#### `highlightedIndex`

The current highlighted (hovered) index.

#### `defaultHighlightedIndex`

The value to set the [`highlightedIndex`](#highlightedindex) whenever the component is reset, when the the selection is cleared,
when an item is selected or when the inputValue is changed.

#### `onItemSelection`

Called when the user selects an item and the selected item has changed.

### `typeaheadRef`

A ref of the Downshift component.

### Types

#### Item

The `node` type is optional because it is not required for passing an initial list of items. But it is required to return
a node in the custom filtering in order to display the items list. The [`items`](#items) type would be `Item[]`.

```ts
interface Item {
  value: string;
  id: string;
  node?: React.ReactNode;
}
```

#### TypeaheadOptions

The options that are returned in the [`handleStateChange`](#handlestatechange) function.

```ts
interface TypeaheadOptions {
  type: string;
  isOpen: boolean;
  inputValue?: string;
  highlightedIndex?: number;
  selectedItem?: Item;
}
```
