Honeycomb

legacy-autocomplete

Deprecated

This component is deprecated since v12.0.0. It is being kept to ease the transition to the new Autocomplete. If you are using this component, please consider migrating to the new one, as it is easier to use and has more features.

Props

Prop nameTypeDefaultDescription
idstring | undefined

Component container id. Overrides automatically generated portion of children ids if needed.

childrenLegacyAutocompleteChildrenComponentsRequired

Expects the following components for composition: LegacyAutocompleteInput LegacyAutocompleteOptions LegacyAutocompleteSelectedOptions

debouncenumber | undefined

Built in debounce for onChange

extraClassesstring | undefined

Custom classes name for autocomplete wrapper element

onChangeChangeEventHandler<HTMLInputElement> | undefined

Fired when the input value changes (without debounce) to be used only in edge cases, rely on debounce to avoid excessive requests to your API

onDebounceChangeEventHandler<HTMLInputElement> | undefined

Fired when the input value changes (with debounce)

onDelete((item: LegacyAutocompleteOptionType) => void) | undefined

Fired when the option gets deleted from selected list (only on multiselect mode).

onReset(() => void) | undefined

Fired when "reset" icon is clicked (only on multiselect mode).

onSelect((item: LegacyAutocompleteOptionType) => void) | undefined

Called when a given option is selected wether by click or by pressing "Enter" key.

onOptionFocus((item: LegacyAutocompleteOptionType, event: FocusEvent<Element, Element> | KeyboardEvent<Element>) => void) | undefined

Called when the user focuses on an option using the keyboard arrow keys

onKeyDownKeyboardEventHandler<HTMLDivElement> | undefined

Fired when a key is pressed inside of the LegacyAutocomplete `container`

onFocusFocusEventHandler<HTMLDivElement> | undefined

Fired when the `container` receives focus event

onBlurFocusEventHandler<HTMLDivElement> | undefined

Fired when blur event happens inside of the `container`

optionsLegacyAutocompleteOptionType[] | LegacyAutocompleteGroupType[]Required

Results of autocomplete to be show in dropdown, all extra item props will be returned on select (see onSelect) this allows you to reference them by id (or any other field you need)

optionsSelectedLegacyAutocompleteOptionType[] | undefined

Selected options to be displayed in `AutocompleteSelectedOptions` when present.

optionsListVisibleboolean | undefined

Makes options list visibility controllable by ignoring focus, blur, escape and arrow key events for showing/hiding the list.

valuestring | undefined

Controls component value, should be an array on multiselect mode.

The autocomplete component is intended to be used as search input for simple entities. You should use autocomplete if the size of your select fields get above a given threshold.

Component relies on composition and requires following components to be passed as children:

  • LegacyAutocompleteInput - the input field itself, note that onDebounce and value props need to be passed to the parent LegacyAutocomplete component in order for things to work;
  • LegacyAutocompleteOptions - a dropdown with the list of options, allows for customization of its appearance like number of options to display, passing custom render functions for option elements etc.
  • LegacyAutocompleteSelectedOptions - renders area with the list of selected options when multiselect variation is used.

A simple example to illustrate the concept:

import { LegacyAutocomplete, LegacyAutocompleteOptions, LegacyAutocompleteInput } from '@flixbus/honeycomb-react';

const [data, setData] = React.useState([]);
const [value, setValue] = React.useState('');
const [highlight, setHighlight] = React.useState('');
const [loading, setLoading] = React.useState(false);

// --------------------------
// Mock data and the filter function
const AutocompleteMockData = [
  {
    title: 'Bologna',
    subtitle: 'Don\'t forget to eat tortellini',
  },
  {
    title: 'Belo Horizonte',
    subtitle: 'Ready for a really long ride?',
  },
  {
    title: 'Belgium',
    subtitle: '🍫 and 🍻',
  },
  {
    title: 'Bermuda',
    subtitle: 'Bring your 🎣',
  },
  {
    title: 'Berlin',
    subtitle: 'The place to be',
  },
];

const filterAutocompleteMockData = (searchQuery, data) => (
  new Promise((resolve) => {
    setTimeout(() => {
      const res = data.filter(item => (
        item.title.toLowerCase().includes(searchQuery.toLowerCase())
      ));
      resolve(res);
    }, 200);
  })
);
// --------------------------
<LegacyAutocomplete
  onChange={(e) => {
    setLoading(true)
  }}
  onDebounce={(e) => {
    setLoading(true);
    setHighlight(e.target.value);
    filterAutocompleteMockData(e.target.value, AutocompleteMockData).then(
      options => {
        setData(options)
        setLoading(false)
      }
    )
  }}
  onSelect={(item) => {
    setData([]);
    setHighlight();
    setValue(item.title);
  }}
  options={data}
  value={value}
>
  {/* configures input field appearance */}
  <LegacyAutocompleteInput
    id="autocomplete-1"
    placeholder="Try to type Berlin slowly"
    label="Place:"
    loading={loading}
    type="search"
    autoComplete="off"
    info={data.length === 0 ? 'No options found.' : `${data.length} option${data.length > 1 ? 's' : ''}.`}
  />
  {/* displays a dropdown with options */}
  <LegacyAutocompleteOptions
    label="Places"
    optionsToDisplay={2}
    optionHasSubtitle
    highlightQuery={highlight}
  />
</LegacyAutocomplete>

Please pay attention to the following things:

  • options and value props are passed to the parent LegacyAutocomplete component;
  • onDebounce and onSelect callbacks are used to filter through the options and control option selection;
  • loading prop of the Input component gets set to true when new data is fetched;
  • we recommend specifying type="search" to the Input as it's more appropriate for this case;
  • check the documentation for LegacyAutocompleteOptions component to find more about customization possibilities for the options list;
  • you can make the LegacyAutocompleteInput visually hidden by using the srOnly helper class name, this way the message is still read out by screen readers;
  • to enable the screen reader to react to changes on the input info, add aria-live="polite" to the element;

Here is the same example illustrating the LegacyAutocompleteInput element customization:

import { LegacyAutocomplete, LegacyAutocompleteOptions, LegacyAutocompleteInput, a11yHelpers } from '@flixbus/honeycomb-react';
import { Icon, IconPinSolid } from '@flixbus/honeycomb-icons-react';

const [data, setData] = React.useState([]);
const [value, setValue] = React.useState('');
const [highlight, setHighlight] = React.useState();
const [loading, setLoading] = React.useState(false);
const inputEl = React.useRef(null);

// --------------------------
// Mock data and the filter function
const AutocompleteMockData = [
  {
    title: 'Bologna',
    subtitle: 'Don\'t forget to eat tortellini',
  },
  {
    title: 'Belo Horizonte',
    subtitle: 'Ready for a really long ride?',
  },
  {
    title: 'Belgium',
    subtitle: '🍫 and 🍻',
  },
  {
    title: 'Bermuda',
    subtitle: 'Bring your 🎣',
  },
  {
    title: 'Berlin',
    subtitle: 'The place to be',
  },
];

const filterAutocompleteMockData = (searchQuery, data) => (
  new Promise((resolve) => {
    setTimeout(() => {
      const res = data.filter(item => (
        item.title.toLowerCase().includes(searchQuery.toLowerCase())
      ));
      resolve(res);
    }, 200);
  })
);
// --------------------------

<LegacyAutocomplete
  options={data}
  value={value}
  onChange={(e) => {
    setLoading(true);
  }}
  onDebounce={(e) => {
    setLoading(true);
    setHighlight(e.target.value);
    filterAutocompleteMockData(e.target.value, AutocompleteMockData).then(
      options => {
        setData(options);
        setLoading(false);
      }
    )
  }}
  onSelect={(item) => {
    setValue(item.title);
    setData([]);
    setHighlight();
  }}
>
  {/* configures input field appearance */}
  <LegacyAutocompleteInput
    id="autocomplete-2"
    placeholder="Try to type Berlin slowly"
    iconLeft={<Icon InlineIcon={IconPinSolid} />}
    label="Place:"
    loading={loading}
    type="search"
    autoComplete="off"
    info={(
      <span aria-live="polite" className={a11yHelpers().srOnly}>
        {data.length === 0 ? 'No options found.' : `${data.length} option${data.length > 1 ? 's' : ''}.`}
      </span>
    )}
  />
  {/* displays a dropdown with options */}
  <LegacyAutocompleteOptions
    label="Places"
    highlightQuery={highlight}
  />
</LegacyAutocomplete>

Multiselect

Passing LegacyAutocompleteSelectedOptions component as child allows for implementing selecting multiple values from the list.

Please note, you'll need to take care of handling selected values and options on your own, our component exposes a set of callback props (onSelect, onDelete, onReset), as well as optionsSelected prop displaying the selected items, giving you a great amount of flexibility in implementing this in a way it works for your app.

Bellow is an example implementation with handful comments that you can take as a basis for more complex solutions:

import { LegacyAutocomplete, LegacyAutocompleteOptions, LegacyAutocompleteSelectedOptions, LegacyAutocompleteInput } from '@flixbus/honeycomb-react';
// a data set we'll be working with
const [data, setData] = React.useState([]);
// storing value as an array of title properties from the data set
const [value, setValue] = React.useState(['Bologna']);
// the input content with the parts that should be highlighted in the options
const [highlight, setHighlight] = React.useState();
// stores selection options, get's populated from data set
const [selectedOptions, setSelectedOptions] = React.useState([])

// --------------------------
// Mock data and the filter function
const AutocompleteMockData = [
  {
    title: 'Bologna',
    subtitle: 'Don\'t forget to eat tortellini',
  },
  {
    title: 'Belo Horizonte',
    subtitle: 'Ready for a really long ride?',
  },
  {
    title: 'Belgium',
    subtitle: '🍫 and 🍻',
  },
  {
    title: 'Bermuda',
    subtitle: 'Bring your 🎣',
  },
  {
    title: 'Berlin',
    subtitle: 'The place to be',
  },
];

const filterAutocompleteMockData = (searchQuery, data) => (
  new Promise((resolve) => {
    setTimeout(() => {
      const res = data.filter(item => (
        item.title.toLowerCase().includes(searchQuery.toLowerCase())
      ));
      resolve(res);
    }, 200);
  })
);
// --------------------------

// narrows down suggested options list based on user input
const filterOptionsList = (e) => {
  setHighlight(e.target.value)
  filterAutocompleteMockData(e.target.value, AutocompleteMockData).then(
    (options) => {
      setData(options);
    },
  );
};
// returns options that have their values stored
const setSelectedOptionsFromValue = (value) => {
  setSelectedOptions(
    AutocompleteMockData.filter(option => value.includes(option.title))
  );
};
// updating selected options every time a value gets updated
React.useEffect(() => {
    setSelectedOptionsFromValue(value);
  }, [value]
);
// pushes selected option value to the state
const handleItemSelect = (selectedItem) => {
  if (!value.includes(selectedItem.title)) {
    setValue(value.concat([selectedItem.title]));
  }
  setHighlight()
  setData([]); // hiding the options list
};
// removes deleted option value from the state
const handleItemDelete = (selectedItem) => {
  setValue(value.filter(valueItem => valueItem !== selectedItem.title));
};
// clears value
const handleReset = () => {
  setValue([]);
}

<LegacyAutocomplete
  placeholder="Try to type Berlin slowly"
  label="Place:"
  options={data}
  // filters the data based on value in the state filling out selected options list
  optionsSelected={selectedOptions}
  onDebounce={filterOptionsList}
  onDelete={handleItemDelete}
  onReset={handleReset}
  onSelect={handleItemSelect}
>
  <LegacyAutocompleteInput
    id="autocomplete-3"
    placeholder="Try to type Berlin slowly"
    label="Place:"
    type="search"
    onFocus={()=>{setData(AutocompleteMockData)}} // allows option list to be shown on focus
  />
  {/* displays a dropdown with options */}
  <LegacyAutocompleteOptions
    label="Places"
    highlightQuery={highlight}
  />
  {/* displays selected options with "clear selection" controls */}
  <LegacyAutocompleteSelectedOptions
    deleteAllItemsLabel="Clear selection"
    deleteItemLabel="Remove item from selection"
  />
</LegacyAutocomplete>