Build a React Autocomplete Component from scratch

Build a React Autocomplete Component from scratch

Create a React Autocomplete component for all your apps

Autocomplete provides a superior user experience to your app’s visitors. It also helps to avoid redundant spelling errors while searching.

In this post, we’ll build a React auto-complete component from scratch.

Then, you can just share it to your Bit collection, and use it in all your apps! It will become a reusable Lego-piece you can use to build faster and share with others.

Example: React spinners with Bit- choose, learn, use

You can get the options from an AJAX request through API, or database. You have a choice for the options shown. Just load them into an array.

Here’s what the end product will look like.

What we’re building

The code for the project is available here on codesandbox, and is also embedded at the end of the post.

App
  >Autocomplete

The Autocomplete component has a container component App, it passes the options to the Autocomplete component in an Array.

import React, { Component } from 'react';
import './App.css';
import Autocomplete from './Autocomplete';
const App = () => {
  return (
    <div className="App">
      <Autocomplete
        options={[
          'Papaya',
          'Persimmon',
          'Paw Paw',
          'Prickly Pear',
          'Peach',
          'Pomegranate',
          'Pineapple'
        ]}
      />
    </div>
  );
};
export default App;

Autocomplete Component

This is where everything happens. I grabbed the initial search box from here on codepen. Emptied default index.css and filled with new CSS.

Here’s how the initial Autocomplete component looks like.

import React, { Component } from 'react';
export class Autocomplete extends Component {
  render() {
    return (
      <React.Fragment>
        <div className="search">
          <input type="text" className="search-box" />
          <input type="submit" value="" className="search-btn" />
        </div>
      </React.Fragment>
    );
  }
}
export default Autocomplete;

Data Validation

Autocomplete component is useless without the options. Options need to be validated as an array to catch the data-type errors quickly. React PropTypes do this exact thing.

They can also flag props as mandatory or set default values.

import PropTypes from 'prop-types';

Options can be marked as Mandatory and Array type within the class by using

static propTypes = {
  options: PropTypes.instanceOf(Array).isRequired;
};

If you do not pass options from parent component, it’ll throw an error on the console.

Here’s the output of our code so far…

Well, it does nothing.

User Inputs

A user can:

  • Change the active option with up/down arrow keys.
  • Select option by clicking with a mouse-click or pressing Return (Enter) key.

Methods Required:

onChange: to check options when input changes

onKeyDown: to check return and arrow keys

value: onChange blocks user from typing into the input field, so we have to fill the value this way.

States Required:

showOptions: boolean (true/false)

filteredOptions: array of items that match with user input.

activeOption: location of currently selected item in filteredOptions, index (Number).

optionList will render JSX with options (in <ul>) that user can choose from. The rendered JSX uses states, and is re-rendered when state is changed.

There will be a lot of places to use this.state.filteredOptions or this.onChange. I like to keep names short, so I used object destructuring for all states and methods.

Here’s how Autocomplete looks now.

import React, { Component } from 'react';
import PropTypes from 'prop-types';
export class Autocomplete extends Component {
  static propTypes = {
    options: PropTypes.instanceOf(Array).isRequired
  };
  state = {
    activeOption: 0,
    filteredOptions: [],
    showOptions: false,
    userInput: ''
  };
  render() {
    const {
      onChange,
      onChange,
      onKeyDown,
      userInput,
      state: { activeOption, filteredOptions, showOptions, userInput }
    } = this;
    let optionList;
    return (
      <React.Fragment>
        <div className="search">
          <input
            type="text"
            className="search-box"
            onChange={onChange}
            onKeyDown={onKeyDown}
            value={userInput}
          />
          <input type="submit" value="" className="search-btn" />
          {optionList}
        </div>
      </React.Fragment>
    );
  }
}
export default Autocomplete;

onChange

When the user makes changes in the input field, we’d like a few things to happen.

onChange = (e) => {
    const { options } = this.props;
    const userInput = e.currentTarget.value;
const filteredOptions = options.filter(
      (option) => option.toLowerCase().indexOf(userInput.toLowerCase()) > -1
    );
this.setState({
      activeOption: 0,
      filteredOptions,
      showOptions: true,
      userInput
    });
  };

It gets options from props, options are used for suggestions. Also, sets userInput to target value (input field).

It filters the options to filteredOptions, the filtering condition being userInput sub-string of the value in array.

First item(index 0) infilteredOptions is the default selected item. This list directly affects the optionList.

onClick

onClick = (e) => {
    this.setState({
      activeOption: 0,
      filteredOption: [],
      showOptions: false,
      userInput: e.currentTarget.innerText
    });
  };

It turns suggestions off and puts text from the clicked element into the input field.

onKeyDown

It handles keyDown events.

Return key (13) does the same thing as the click event, selects the item and puts a value to the input field.

Down arrow(40) selects the lower option. Up arrow (38) selects the upper option. But it won’t go below last or above the first option.

onKeyDown = (e) => {
    const { activeOption, filteredOptions } = this.state;
if (e.keyCode === 13) {
      this.setState({
        activeOption: 0,
        showSuggestions: false,
        userInput: filteredOptions[activeOption]
      });
    } else if (e.keyCode === 38) {
      if (activeOption === 0) {
        return;
      }
this.setState({ activeOption: activeOption - 1 });
    } else if (e.keyCode === 40) {
      if (activeOption - 1 === filteredOptions.length) {
        return;
      }
this.setState({ activeOption: activeOption + 1 });
    }
  };

If you use React Dev Tools, you can see the changes there…

Now, it’s time to get these state changes to the interface and let users select an option.

The optionList

optionList is the option selection interface for the end-user.

let optionList;
    if (showOptions && userInput) {
      if (filteredOptions.length) {
        optionList = (
          <ul className="options">
            {filteredOptions.map((optionName, index) => {
              let className;
              if (index === activeOption) {
                className = 'option-active';
              }
              return (
                <li className={className} key={optionName} onClick={onClick}>
                  {optionName}
                </li>
              );
            })}
          </ul>
        );
      } else {
        optionList = (
          <div className="no-options">
            <em>No Option!</em>
          </div>
        );
      }
    }

showOptions is true, and input area is not blank.

It goes through the filteredOptions to create a list. Additionally, active option gets option-active className. This is styled using css in index.css.

Here’s what it looks like.

If the input field value does not match with anything, it says no option.

Codesandbox demo is embedded below.

Conclusion

So we’ve created an auto-complete component your users can enjoy, creating a better experience for your product. It will help them reduce confusion and mistakes, and quickly navigate their way through your application.

Please feel free to comment and ask me anything! I’d be happy to help :)

Originally published on https://blog.bitsrc.io

reactjs javascript web-development

Bootstrap 5 Complete Course with Examples

Bootstrap 5 Tutorial - Bootstrap 5 Crash Course for Beginners

Nest.JS Tutorial for Beginners

Hello Vue 3: A First Look at Vue 3 and the Composition API

Building a simple Applications with Vue 3

Deno Crash Course: Explore Deno and Create a full REST API with Deno

How to Build a Real-time Chat App with Deno and WebSockets

Convert HTML to Markdown Online

HTML entity encoder decoder Online

Hire Web Developer

Looking for an attractive & user-friendly web developer? HourlyDeveloper.io, a leading web, and mobile app development company, offers web developers for hire through flexible engagement models. You can **[Hire Web...

ReactJS Web App Development Services

We provide top-notch ReactJS development services to global clients. Hire expert ReactJS developers from top React JS development company, Skenix Infotech.

Why Web Development is Important for your Business

With the rapid development in technology, the old ways to do business have changed completely. A lot more advanced and developed ways are ...

Important Reasons to Hire a Professional Web Development Company

    You name the business and I will tell you how web development can help you promote your business. If it is a startup or you seeking some...

Hire Dedicated eCommerce Web Developers | Top eCommerce Web Designers

Build your eCommerce project by hiring our expert eCommerce Website developers. Our Dedicated Web Designers develop powerful & robust website in a short span of time.