Autocomplete and Search in Forms

Loading

Autocomplete and search functionalities are common features in web forms, allowing users to search and select from a list of options quickly. These features enhance the user experience by providing suggestions as the user types and reducing the chance of errors.

In React, you can implement autocomplete and search in forms using native HTML elements or third-party libraries. Let’s explore different methods of adding these features to React forms.


1. Autocomplete Using Native HTML datalist Element

HTML provides a built-in datalist element that can be used for autocomplete functionality. This works well for simple autocomplete needs.

Example: Simple Autocomplete with datalist

import React, { useState } from 'react';

const AutocompleteForm = () => {
  const [selectedOption, setSelectedOption] = useState('');

  const options = ['Apple', 'Banana', 'Orange', 'Grape', 'Pineapple'];

  const handleChange = (e) => {
    setSelectedOption(e.target.value);
  };

  return (
    <form>
      <label htmlFor="fruit">Select a fruit: </label>
      <input
        list="fruits"
        id="fruit"
        name="fruit"
        value={selectedOption}
        onChange={handleChange}
      />
      <datalist id="fruits">
        {options.map((option, index) => (
          <option key={index} value={option} />
        ))}
      </datalist>
    </form>
  );
};

export default AutocompleteForm;

Explanation:

  • The datalist element provides a list of predefined options for the input field.
  • As the user types, the input will show suggestions based on the available options.
  • This is a simple and native solution for autocomplete.

2. Autocomplete with Search Using react-select

For more complex search and autocomplete features (e.g., async data fetching, custom styling), libraries like react-select offer a highly customizable and feature-rich solution.

Example: Autocomplete with react-select

npm install react-select
import React, { useState } from 'react';
import Select from 'react-select';

const AutocompleteWithReactSelect = () => {
  const [selectedOption, setSelectedOption] = useState(null);

  const options = [
    { value: 'apple', label: 'Apple' },
    { value: 'banana', label: 'Banana' },
    { value: 'orange', label: 'Orange' },
    { value: 'grape', label: 'Grape' },
    { value: 'pineapple', label: 'Pineapple' },
  ];

  const handleChange = (selected) => {
    setSelectedOption(selected);
  };

  return (
    <form>
      <label>Select a fruit: </label>
      <Select
        value={selectedOption}
        onChange={handleChange}
        options={options}
        isClearable
        isSearchable
      />
    </form>
  );
};

export default AutocompleteWithReactSelect;

Explanation:

  • react-select is a popular library that provides powerful search, autocomplete, and multi-select capabilities.
  • The isSearchable prop enables the search feature, while isClearable allows clearing the selection.
  • This solution is ideal for more complex cases, such as dynamic data fetching, custom filtering, and styling.

3. Search with API Call (Async Data)

Sometimes, the list of options for autocomplete needs to be fetched dynamically from an API. In such cases, we can use libraries like react-select along with asynchronous data fetching.

Example: Autocomplete with Async API Call

import React, { useState } from 'react';
import Select from 'react-select';
import axios from 'axios';

const AsyncAutocomplete = () => {
  const [options, setOptions] = useState([]);
  const [selectedOption, setSelectedOption] = useState(null);

  const fetchOptions = async (inputValue) => {
    if (!inputValue) return [];

    const response = await axios.get(`https://api.example.com/search?q=${inputValue}`);
    return response.data.map((item) => ({
      value: item.id,
      label: item.name,
    }));
  };

  const handleChange = (selected) => {
    setSelectedOption(selected);
  };

  return (
    <form>
      <label>Select an option: </label>
      <Select
        value={selectedOption}
        onChange={handleChange}
        loadOptions={fetchOptions}
        cacheOptions
        defaultOptions
        isClearable
        isSearchable
      />
    </form>
  );
};

export default AsyncAutocomplete;

Explanation:

  • Async Data Fetching: The fetchOptions function fetches data from an API based on the user’s input.
  • loadOptions: This prop is used in react-select to load options asynchronously.
  • cacheOptions: This ensures that previously fetched options are cached for improved performance.

4. Custom Autocomplete with useState and Filter Logic

If you prefer to build a custom autocomplete or search solution without third-party libraries, you can use basic React hooks and filtering logic.

Example: Custom Autocomplete with useState

import React, { useState } from 'react';

const CustomAutocomplete = () => {
  const [query, setQuery] = useState('');
  const [selectedOption, setSelectedOption] = useState('');
  const [filteredOptions, setFilteredOptions] = useState([]);

  const options = ['Apple', 'Banana', 'Orange', 'Grape', 'Pineapple'];

  const handleChange = (e) => {
    const value = e.target.value;
    setQuery(value);
    const filtered = options.filter((option) =>
      option.toLowerCase().includes(value.toLowerCase())
    );
    setFilteredOptions(filtered);
  };

  const handleSelect = (option) => {
    setSelectedOption(option);
    setQuery(option);
    setFilteredOptions([]);
  };

  return (
    <div>
      <label>Select a fruit: </label>
      <input
        type="text"
        value={query}
        onChange={handleChange}
        placeholder="Search fruits"
      />
      {filteredOptions.length > 0 && (
        <ul>
          {filteredOptions.map((option, index) => (
            <li key={index} onClick={() => handleSelect(option)}>
              {option}
            </li>
          ))}
        </ul>
      )}
      {selectedOption && <div>Selected: {selectedOption}</div>}
    </div>
  );
};

export default CustomAutocomplete;

Explanation:

  • Custom Search Logic: The handleChange function filters the options based on the user’s input and updates the filteredOptions state.
  • Select Option: When an option is clicked, it updates the selectedOption state and clears the filtered list.

5. Search with Debouncing

To avoid making API calls on every keystroke (especially in case of slow networks), you can implement debouncing to limit the number of requests or filter operations.

Example: Debounced Search

npm install lodash.debounce
import React, { useState } from 'react';
import debounce from 'lodash.debounce';

const DebouncedSearch = () => {
  const [query, setQuery] = useState('');
  const [results, setResults] = useState([]);

  const search = (query) => {
    // Simulate an API call
    const filteredResults = ['Apple', 'Banana', 'Orange', 'Grape', 'Pineapple'].filter((item) =>
      item.toLowerCase().includes(query.toLowerCase())
    );
    setResults(filteredResults);
  };

  const debouncedSearch = debounce((query) => search(query), 500);

  const handleChange = (e) => {
    const value = e.target.value;
    setQuery(value);
    debouncedSearch(value);
  };

  return (
    <div>
      <label>Search Fruits: </label>
      <input type="text" value={query} onChange={handleChange} />
      <ul>
        {results.map((result, index) => (
          <li key={index}>{result}</li>
        ))}
      </ul>
    </div>
  );
};

export default DebouncedSearch;

Explanation:

  • Debouncing: Using lodash.debounce, the debouncedSearch function is called after 500ms of inactivity, which reduces the number of calls to the search function.
  • Filtering: The list is filtered based on the user’s input, and the results are displayed below the input field.

Leave a Reply

Your email address will not be published. Required fields are marked *