Make Combobox / Dropdown Input with React & TypeScript

October 31, 2022

3 min read

Make Combobox / Dropdown Input with React & TypeScript
Watch on YouTube

Let's make a text input with fixed options, where the user gets suggestions while typing, but they can only "submit" the field with a value from the list of options. Here, we have an example of an input where you can select languages you know.

combobox

The LanguagesInput component receives an array of selected languages, the onChange callback, and an optional error message. It consists of two parts: the FixedOptionsInput and a list of entered languages. The most sophisticated piece here is the Combobox component. First, we pass properties common to form fields: label, placeholder, error, ref, onChange, and value, which is null because we don't preselect any value. Then we provide options that could be of any type, so we follow with a string convertor. To clear the input after choosing a language, we pass the clearAfterOptionSelected flag. We can also provide a render option function to display a custom element in the list of suggestions.

<FixedOptionsInput
  label="Languages"
  placeholder="Spanish"
  value={null}
  ref={ref}
  onChange={(value) => {
    if (value) {
      handleAddLanguage(value)
    }
  }}
  error={error}
  optionToString={(option) => option}
  options={availableLanguageNames}
  clearAfterOptionSelected
/>

The parent element for the combo box is a div, for which we set up ref, and the onBlur callback to close the menu when inner elements are out of focus. Then we have an input wrapper for providing a label and error message together with an absolutely positioned button to toggle men open state. I covered both the InputWrapperWithErrorMessage and TextInputContainer in another post.

To display suggestions, we have the DropdownMenuPlacer component. We pass input as children and a list of options to the placer, and it sets up refs to position the menu right under the input. To show the menu with are using the react-popper library. Here we set up a config to show the menu on top in case there is not enough space, then we add a margin between the input and the menu. Finally, we make the menu the same width as the input.

The ComboboxOptions component takes a list of suggestions and renders them inside a container that sets a specific max height together with overflow-y set to auto to show a scroll. We store refs of every option to scroll into view a selected one. To allow moving between suggestions with keyboards, we are using a combination of the user keypress hook together with the getHandleStep function.

The FixedOptionsInput has some tricky effects managing input and menu with suggestions. We won't go deep into them, but if you're curious, welcome to explore them on GitHub.