Autocomplete Search Feature using Downshift

  1. useLazyQuery from Apollo GraphQL Queries
  2. Downshift API

GraphQL Query

KeystoneJS auto creates graphQL queries based on our schema. E.g. if we have a Products schema. One of the generated queries is allProducts which allows us queries for all products in the database. Also, we are given a number of ways to filter, sort, limit our items e.g. the where filters.

No Data Returned?

If there is no data returned from the query and we have tried divide and conquer in the debugging process to make sure:

  • input into the query was correct- e.g. hardcoding the input
  • graphQL API does return correct data —e.g. hardcoding inputs in graphQL playground
  • queries are called as expected — e.g. console.log in the function

Downshift Autocomplete Widget

Downshift is a popular, well tested ARIA compliant React autocomplete component. In our case, we can use the useCombobox hook to get a list of APIs for setting up our autocomplete Search input with our custom styles.

APIs: getComboboxProps, getInputProps, getMenuProps…

These prop getters corresponds to the different parts of a dropdown selection box as seen from the diagram above.

// e.g.
<input
{...getInputProps({
type: 'search',
id: 'search'
})}
/>

useCombobox: 3 inputs here

  • onInputValueChange(): this method if called when user starts typing in the Search box. We call the useLazyQuery here to get a list of matching products to be displayed in the dropdown menu!
  • onSelectedItemChange(): this method is called when user selects an item in the dropdown menu. We want to take the user to the corresponding product page so we update the routes here!
  • itemToString(): Downshift needs a string representation of the item. If our item is an object structure, we need to return a string representation for Downshift

Other Things to note

  • getItemProps() needs to be set in order for onSelectedItemChange() to be called
  • The highlighted styling can be enabled by matching the highlightedIndex from useCombobox with the item.index
  • To make the dropdown menu hide when we click away, as can use the isOpen property from useCombobox. Only When isOpen is true, we run through items.map
  • To handle to noFound case, we can check for the condition (isOpen && !items.length && !loading)
  • If we are using Downshift in SSR e.g. NextJS, we need to synchronise IDs generated in server and client using resetidcounter.

--

--

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store
Sherry Hsu

Sherry Hsu

311 Followers

A software engineer passionate about learning and growth