Autocomplete is a feature in which an input field suggests a word based on user input. This helps improve the user experience in your application, such as cases where a search is necessary.
In this article, you will examine how to build an autocomplete component in React. You will work with a fixed list of suggestions, event binding, understanding keyboard codes, and operate state management.
To complete this tutorial, you will need the following:
Autocomplete
ComponentThe Autocomplete
component is where you will craft the functionality in the autocomplete feature.
Create an Autocomplete.js
file, and import React and instantiate an Autocomplete
class:
import React, { Component, Fragment } from "react";
import './styles.css'
class Autocomplete extends Component {
constructor(props) {
super(props);
this.state = {
activeSuggestion: 0,
filteredSuggestions: [],
showSuggestions: false,
userInput: ""
};
}
On your state, the activeSuggestion
property defines the index of a selected suggestion. The property filteredSuggestions
, set to an empty array, matches the user’s input. The showSuggestions
property will determine whether or not the the suggestion list appears, and the userInput
property assigns itself an empty string for accepting a word from a user’s input.
With your class started and state set, let’s look at the methods to apply in the component.
In your Autocomplete.js
file, define an onChange
method and update your state:
onChange = e => {
const { suggestions } = this.props;
const userInput = e.currentTarget.value;
const filteredSuggestions = suggestions.filter(
suggestion =>
suggestion.toLowerCase().indexOf(userInput.toLowerCase()) > -1
);
this.setState({
activeSuggestion: 0,
filteredSuggestions,
showSuggestions: true,
userInput: e.currentTarget.value
});
};
The method onChange
will fire when the user changes the input value. On each change, the method will filter into the suggestion list and return suggestions that do not contain the user’s input. Once the filter runs through, the .setState()
method will revise your state’s userInput
property to contain a value, set your showSuggestions
boolean to allow suggestions to show, and reset the activeSuggestion
property on each method call.
The onClick
event will invoke when the user clicks on a suggestion. In your Autocomplete.js
file, declare an onClick
method and implement a .setState()
method:
onClick = e => {
this.setState({
activeSuggestion: 0,
filteredSuggestions: [],
showSuggestions: false,
userInput: e.currentTarget.innerText
});
};
The .setState()
method will update the user’s input and reset your state’s properties.
The onKeyDown
method will engage when the user presses a key down. In your Autocomplete.js
file, declare an onKeyDown
method and set several conditionals:
onKeyDown = e => {
const { activeSuggestion, filteredSuggestions } = this.state;
if (e.keyCode === 13) {
this.setState({
activeSuggestion: 0,
showSuggestions: false,
userInput: filteredSuggestions[activeSuggestion]
});
} else if (e.keyCode === 38) {
if (activeSuggestion === 0) {
return;
}
this.setState({ activeSuggestion: activeSuggestion - 1 });
}
// User pressed the down arrow, increment the index
else if (e.keyCode === 40) {
if (activeSuggestion - 1 === filteredSuggestions.length) {
return;
}
this.setState({ activeSuggestion: activeSuggestion + 1 });
}
};
Once you’ve stored your properties activeSuggestion
and filteredSuggestion
in a deconstructed object, the conditionals will check if the key the user pressed down matches the key codes. The first conditional will check if the key code matches 13
, the enter key, and run the .setState()
method to update the userInput
property and close the suggestions list. If the user pressed the up arrow, the key code 38
, the conditional will decrement the index of the activeSuggestion
property, and return nothing if the index is zero. If the user pressed the down arrow, the key code 40
, the conditional will increment the index in the activeSuggestion
property, and return nothing if the index matches the length of the filteredSuggestions
property.
With your methods now complete, let’s navigate to applying your render
lifecycle method.
In your Autocomplete.js
file, set a render()
statement, and define your methods and state in a deconstructed object:
render() {
const {
onChange,
onClick,
onKeyDown,
state: {
activeSuggestion,
filteredSuggestions,
showSuggestions,
userInput
}
} = this;
let suggestionsListComponent;
The variable suggestionsListComponent
has no defined value as you will assign them in the conditionals below:
if (showSuggestions && userInput) {
if (filteredSuggestions.length) {
suggestionsListComponent = (
<ul class="suggestions">
{filteredSuggestions.map((suggestion, index) => {
let className;
// Flag the active suggestion with a class
if (index === activeSuggestion) {
className = "suggestion-active";
}
return (
<li className={className} key={suggestion} onClick={onClick}>
{suggestion}
</li>
);
})}
</ul>
);
} else {
suggestionsListComponent = (
<div class="no-suggestions">
<em>No suggestions available.</em>
</div>
);
}
}
The first conditional will check if the values on the properties showSuggestions
and userInput
exists, while the following condition will check for the length of the filteredSuggestions
property. If the conditionals are met, the suggestionsListComponent
variable assigns itself the value of iterating through the filteredSuggestions
property and flag an active suggestion with a class name if the index matches the value in the activeSuggestion
property. The suggestionsListComponent
variable will return an ordered list of the suggestions upon execution of the onClick
method, and assign each suggestion a class name. If the values on the properties showSuggestions
and userInput
do not exist, a text will appear to indicate no there are no suggestions available.
If the user does not meet the conditions listed, the render()
lifecycle method will return a React Fragment
to apply the input field and invoke the methods without adding extra nodes to the document object model:
return (
<Fragment>
<input
type="text"
onChange={onChange}
onKeyDown={onKeyDown}
value={userInput}
/>
{suggestionsListComponent}
</Fragment>
);
}
}
export default Autocomplete;
Now that you’ve developed your Autocomplete
component, export the file combine its functionality in another component.
The App
component is where you will display the functionality in your Autocomplete
component. In your index.js
file, declare an App
component and import your Autocomplete
component:
import React from "react";
import Autocomplete from "./Autocomplete";
function App() {
return (
<div>
<h1>React Autocomplete Demo</h1>
<h2>Start typing and experience the autocomplete wizardry!</h2>
<Autocomplete suggestions={"Oranges", "Apples", "Banana", "Kiwi", "Mango"]}/>
</div>
);
}
export default App
The return statement in your App
component accepts the Autocomplete
component with the fixed list of suggestions.
Autocomplete
ComponentTo finish your Autocomplete
component, add styling with CSS to position and color your application and input field.
Create a styles.css
file and set CSS rules to shape your Autocomplete
component:
body {
font-family: sans-serif;
}
input {
border: 1px solid #999;
padding: 0.5rem;
width: 300px;
}
.no-suggestions {
color: #999;
padding: 0.5rem;
}
.suggestions {
border: 1px solid #999;
border-top-width: 0;
list-style: none;
margin-top: 0;
max-height: 143px;
overflow-y: auto;
padding-left: 0;
width: calc(300px + 1rem);
}
.suggestions li {
padding: 0.5rem;
}
.suggestion-active,
.suggestions li:hover {
background-color: #008f68;
color: #fae042;
cursor: pointer;
font-weight: 700;
}
.suggestions li:not(:last-of-type) {
border-bottom: 1px solid #999;
}
With your CSS rules constructed, import the file into your Autocomplete.js
file to apply your styles.
React offers measures to construct the autocomplete functionality available in one component with built-in and custom methods to interact with the user.
Check out how the Autocomplete component operates in CodeSandbox.
Thanks for learning with the DigitalOcean Community. Check out our offerings for compute, storage, networking, and managed databases.
This textbox defaults to using Markdown to format your answer.
You can type !ref in this text area to quickly search our full set of tutorials, documentation & marketplace offerings and insert the link!
Good Day,
Just wanted confirm with your code the following:
Shouldn’t the logic at the keyCode === 40 be activeSuggestion + 1 === filteredSuggestions.length as you increase your position when pressing the down arrow.
Please let me know if I am correct.
Great stuff exactly what I was looking for!
suggestion list scrolling is not happening with keyboard up and down arrow keys. please update code. Thanks
Hi Josh, this is great, exactly what I was looking for! I have a follow-up question - in case of a larger textarea, I would like the auto-complete to show somewhere below or above the current cursor position (not under the input box) - any tips on how to achieve this? Thanks