Autocomplete Text Input
Develop a text input that suggests possible completions as the user types, pulling from a predefined list of options.
Solution
Explanation
Input and Autocomplete Logic
The input field allows users to type in the name of a programming language. The component has a state for the input
value and a highlightedSuggestion
, which holds the first matching suggestion from the programmingLanguages
array.
As the user types, the handleChange
function is called, updating the input value and filtering the array for languages that match the current input. If any match is found, the first one is displayed as the suggestion.
Handling Autocomplete Suggestions
The suggestion system works by comparing the user's input to the start of each item in the programmingLanguages
array. The match is case-insensitive and the first match is set as the autocomplete suggestion, which is visually hinted to the user.
If no match is found, or the input field is empty, the highlightedSuggestion
is cleared, and no hint is displayed. This ensures that irrelevant suggestions are not shown.
Handling Keyboard Events
The handleKeyDown
function captures theTab
key press event. If the user presses Tab
and there is a suggestion available, the input is automatically filled with the suggestion.
The function also prevents the default tab behavior to avoid shifting focus when auto-completing the input. This makes the suggestion process more fluid for the user.
CSS Styling for Autocomplete
The CSS controls both the input field and the autocomplete suggestion. The autocompleteWrapper
ensures the suggestion is positioned correctly and doesn't interfere with the input. The suggestion is styled to overlay on top of the input field, with part of the text displayed in light grey to indicate what will be completed.
The input text that has already been typed is set to transparent to visually merge with the suggestion. This gives the user the illusion that they are typing, while the suggestion helps guide them to complete the input.
Code
import { useState } from "react";
import styles from "./Solution.module.css";
const programmingLanguages = [
"C",
"C#",
"C++",
"Go",
"Java",
"JavaScript",
"Kotlin",
"Perl",
"PHP",
"Python",
"R",
"Ruby",
"Rust",
"SQL",
"Swift",
"TypeScript",
];
const Solution = () => {
const [input, setInput] = useState("");
const [highlightedSuggestion, setHighlightedSuggestion] = useState("");
const handleChange = (value: string) => {
setInput(value);
const updatedList = programmingLanguages.filter((item) =>
item.toLowerCase().startsWith(value.toLowerCase())
);
// Set the first suggestion for the autocomplete hint
if (updatedList.length > 0 && value) {
setHighlightedSuggestion(updatedList[0]);
} else {
setHighlightedSuggestion("");
}
};
const handleKeyDown = (event: React.KeyboardEvent<HTMLInputElement>) => {
// When the Tab key is pressed
if (event.key === "Tab" && highlightedSuggestion) {
event.preventDefault(); // Prevent focus shift
setInput(highlightedSuggestion); // Set the input to the full suggestion
setHighlightedSuggestion(""); // Clear the autocomplete suggestion
}
};
return (
<>
<label className={styles.label} htmlFor="language">
Input your main programming language
</label>
<div className={styles.autocompleteWrapper}>
<input
onChange={(event) => handleChange(event.target.value)}
onKeyDown={handleKeyDown}
value={input}
className={styles.input}
type="text"
id="language"
/>
{highlightedSuggestion && (
<div className={styles.autocompleteSuggestion}>
<span className={styles.inputText}>{input}</span>
<span className={styles.greyText}>
{highlightedSuggestion.slice(input.length)}
</span>
</div>
)}
</div>
</>
);
};
export default Solution;
Styling
.input {
margin-top: 10px;
padding: 5px;
position: relative;
background: white;
border: 2px solid black;
z-index: 0;
width: 100%;
font-size: inherit;
font-family: inherit;
color: black;
}
.label {
font-weight: bold;
}
/* Autocomplete styles */
.autocompleteWrapper {
position: relative;
display: inline-block;
width: 100%;
}
.autocompleteSuggestion {
margin-top: 10px;
border: 2px solid transparent;
position: absolute;
top: 0;
left: 0;
pointer-events: none;
font-family: inherit;
font-size: inherit;
padding: 5px;
width: 100%;
z-index: 1;
}
.inputText {
color: transparent;
padding: 0;
}
.greyText {
color: lightgrey;
}