React Autocomplete Component Challenge
Build an intelligent and user-friendly autocomplete component for a React application. This component will allow users to type into an input field and receive real-time suggestions based on a provided list of data. This is a common and highly useful feature for enhancing user experience in search bars, forms, and selection inputs.
Problem Description
Your task is to create a reusable React component named Autocomplete that takes a list of options and a callback function for handling selection. The component should:
- Display an Input Field: Render a standard HTML
<input type="text" />element. - Filter Options: As the user types, dynamically filter the provided list of options to show only those that match the current input value (case-insensitive).
- Show Suggestions: Display the filtered suggestions in a dropdown list below the input field.
- Handle Selection: When a user clicks on a suggestion, update the input field with the selected suggestion and trigger a callback function (provided as a prop) with the selected value.
- Handle Keyboard Navigation: Allow users to navigate through suggestions using the Up and Down arrow keys and select a highlighted suggestion by pressing Enter.
- Close Suggestions: The suggestion list should close when the user clicks outside the component or after a selection is made.
Examples
Example 1:
- Input (Props):
options:['Apple', 'Banana', 'Cherry', 'Date', 'Elderberry', 'Fig']onSelect:(value) => console.log('Selected:', value)
- User Interaction:
- User types "a" into the input.
- User types "ap" into the input.
- Expected Behavior:
- Initially, the input is empty, and no suggestions are shown.
- After typing "a", the suggestions
['Apple']are displayed. - After typing "ap", the suggestions
['Apple']are still displayed. - If the user clicks on "Apple", the input shows "Apple", and
onSelectis called with "Apple".
Example 2:
- Input (Props):
options:['United States', 'Canada', 'Mexico', 'Brazil', 'Argentina', 'Chile']onSelect:(value) => console.log('Selected:', value)
- User Interaction:
- User types "u" into the input.
- User types "un" into the input.
- User types "uni" into the input.
- User presses the Down arrow key twice.
- User presses the Enter key.
- Expected Behavior:
- After typing "u", suggestions
['United States']appear. - After typing "un", suggestions
['United States']appear. - After typing "uni", suggestions
['United States']appear. - If a suggestion like
['Canada']was visible and highlighted, pressing Down arrow twice might select['Mexico']. - Pressing Enter should select the currently highlighted suggestion, update the input, and call
onSelect.
- After typing "u", suggestions
Example 3: Case Insensitivity and Empty Input
- Input (Props):
options:['React', 'Vue', 'Angular', 'Svelte']onSelect:(value) => console.log('Selected:', value)
- User Interaction:
- User types "r" into the input.
- User types "R" into the input.
- User clears the input.
- Expected Behavior:
- Typing "r" shows
['React']. - Typing "R" also shows
['React'](case-insensitive matching). - Clearing the input hides all suggestions.
- Typing "r" shows
Constraints
- The
optionsprop will be an array of strings. - The
onSelectprop will be a function that accepts a single string argument. - The component should be built using React and TypeScript.
- For simplicity, assume there are no more than 1000 options.
- The filtering should be reasonably efficient, aiming for a response time under 100ms for typical user typing speeds.
Notes
- Consider how you will manage the state for the input value, the filtered suggestions, and the currently highlighted suggestion for keyboard navigation.
- Styling is not a primary concern for this challenge, but the suggestions should be visually distinct from the input and positioned correctly. You can use basic CSS or inline styles.
- Think about how to handle the scenario where no options match the input.
- Consider using event handlers like
onChange,onKeyDown, andonClickeffectively. - Debouncing the input change event might be a good optimization to avoid excessive filtering on every keystroke, especially for larger datasets or more complex filtering logic.