#AD "Ten++ Ways to Make Money as a Developer" eBook by Florin Pop

Build a custom React autocomplete search component

Last modified October 15th 2021 | #react | GitHub Source Code [GitHub]

In this tutorial we’ll be building a React autocomplete search component that provides suggestions as a user types a search query. There are a number of libraries that provide autocomplete functionality in React but we’ll be creating a custom component from scratch.

Let’s get started by setting up a basic app using Create React App:

npx create-react-app react-autocomplete-search

Next create a new data.js file in the /src folder. This file contains an array that will be used to provide the autocomplete suggestions. In the real world you might want to replace this file with an API call to provide the data:

export const autoCompleteData = [ "Asparagus", "Beetroot", "Broccoli", "Cabbage", "Carrot", "Cauliflower", "Celery", "Corn", "Eggplant", "Lettuce", "Mushroom", "Onion", "Parsnip", "Pea", "Potato", "Pumpkin", "Radish", "Spinach", "Tomato", "Turnip", ];
Code language: JavaScript (javascript)

Then create a new AutoComplete.js file in the /src folder with the following structure:

import { useState } from "react"; const AutoComplete = ({ data }) => { return ( <div className="autocomplete"> <input type="text" /> </div> ); }; export default AutoComplete;
Code language: JavaScript (javascript)

We can now start building the component starting with the State variables:

const [suggestions, setSuggestions] = useState([]); const [suggestionIndex, setSuggestionIndex] = useState(0); const [suggestionsActive, setSuggestionsActive] = useState(false); const [value, setValue] = useState("");
Code language: JavaScript (javascript)
  • suggestions – array of suggestions to used populate the autocomplete menu.
  • suggestionIndex – index of the active suggestion used for keyboard navigation.
  • suggestionsActive – used to toggle the visibility of the autocomplete suggestions.
  • value – autocomplete suggestion that the user has selected.

The autocomplete suggestions need to be triggered while the user is typing a query. For this we’ll use an onChange event that monitors for changes to the input field. We then filter the autoCompleteData to find the relevant suggestions:

const handleChange = (e) => { const query = e.target.value.toLowerCase(); setValue(query); if (query.length > 1) { const filterSuggestions = data.filter( (suggestion) => suggestion.toLowerCase().indexOf(query) > -1 ); setSuggestions(filterSuggestions); setSuggestionsActive(true); } else { setSuggestionsActive(false); } };
Code language: JavaScript (javascript)

Users will also need to be able to click an autocomplete suggestion and have that suggestion populate the input field. For this we’ll need to add the following function that is triggered by an onClick event:

const handleClick = (e) => { setSuggestions([]); setValue(e.target.innerText); setSuggestionsActive(false); };
Code language: JavaScript (javascript)

To allow users to navigate between each of the suggestions and also select a suggestion using the keyboard we’ll use a keyDown event to listen for when either the up/down arrow and enter keys are pressed:

const handleKeyDown = (e) => { // UP ARROW if (e.keyCode === 38) { if (suggestionIndex === 0) { return; } setSuggestionIndex(suggestionIndex - 1); } // DOWN ARROW else if (e.keyCode === 40) { if (suggestionIndex - 1 === suggestions.length) { return; } setSuggestionIndex(suggestionIndex + 1); } // ENTER else if (e.keyCode === 13) { setValue(suggestions[suggestionIndex]); setSuggestionIndex(0); setSuggestionsActive(false); } };
Code language: JavaScript (javascript)

For the actual suggestions we’ll create a Suggestions component:

const Suggestions = () => { return ( <ul className="suggestions"> {suggestions.map((suggestion, index) => { return ( <li className={index === suggestionIndex ? "active" : ""} key={index} onClick={handleClick} > {suggestion} </li> ); })} </ul> ); };
Code language: JavaScript (javascript)

This outputs the suggestions array into an unordered HTML list. Note we’ve added a conditional active class which will allow us to style the list item the user has selected using the up/down arrows on the keyword. You can add the following CSS to see this in action once the component is complete:

.active { background: lightgray; }
Code language: CSS (css)

To complete the component update the return statement as follows:

return ( <div className="autocomplete"> <input type="text" value={value} onChange={handleChange} onKeyDown={handleKeyDown} /> {suggestionsActive && <Suggestions />} </div> );
Code language: JavaScript (javascript)

Here’s how the completed AutoComplete component should look:

import { useState } from "react"; const AutoComplete = ({ data }) => { const [suggestions, setSuggestions] = useState([]); const [suggestionIndex, setSuggestionIndex] = useState(0); const [suggestionsActive, setSuggestionsActive] = useState(false); const [value, setValue] = useState(""); const handleChange = (e) => { const query = e.target.value.toLowerCase(); setValue(query); if (query.length > 1) { const filterSuggestions = data.filter( (suggestion) => suggestion.toLowerCase().indexOf(query) > -1 ); setSuggestions(filterSuggestions); setSuggestionsActive(true); } else { setSuggestionsActive(false); } }; const handleClick = (e) => { setSuggestions([]); setValue(e.target.innerText); setSuggestionsActive(false); }; const handleKeyDown = (e) => { // UP ARROW if (e.keyCode === 38) { if (suggestionIndex === 0) { return; } setSuggestionIndex(suggestionIndex - 1); } // DOWN ARROW else if (e.keyCode === 40) { if (suggestionIndex - 1 === suggestions.length) { return; } setSuggestionIndex(suggestionIndex + 1); } // ENTER else if (e.keyCode === 13) { setValue(suggestions[suggestionIndex]); setSuggestionIndex(0); setSuggestionsActive(false); } }; const Suggestions = () => { return ( <ul className="suggestions"> {suggestions.map((suggestion, index) => { return ( <li className={index === suggestionIndex ? "active" : ""} key={index} onClick={handleClick} > {suggestion} </li> ); })} </ul> ); }; return ( <div className="autocomplete"> <input type="text" value={value} onChange={handleChange} onKeyDown={handleKeyDown} /> {suggestionsActive && <Suggestions />} </div> ); }; export default AutoComplete;
Code language: JavaScript (javascript)

Finally we can update App.js to load the component and the data:

import Autocomplete from "./AutoComplete"; import { autoCompleteData } from "./data.js"; function App() { return ( <div className="App"> <Autocomplete data={autoCompleteData} /> </div> ); } export default App;
Code language: JavaScript (javascript)

That’s all for this tutorial, you should now have a working autocomplete search component that can easily be dropped into a React application. You can get the full source code for this tutorial and all tutorials published on w3collective from GitHub.

Related Posts