Skip to main content

Autocomplete

Autocomplete.tsx
import React, { useState, useEffect, useRef } from 'react';
import styles from './Autocomplete.module.css';

interface AutocompleteProps {
options: string[];
onSelect: (value: string) => void;
}

const Autocomplete = ({ options, onSelect }: AutocompleteProps) => {
const [inputValue, setInputValue] = useState('');
const [filteredOptions, setFilteredOptions] = useState<string[]>([]);
const [activeIndex, setActiveIndex] = useState(-1);
const inputRef = useRef<HTMLInputElement>(null);

useEffect(() => {
const filtered = options.filter((option) =>
option.toLowerCase().includes(inputValue.toLowerCase())
);
setFilteredOptions(filtered);
setActiveIndex(-1);
}, [inputValue, options]);

const handleInputChange = (event: React.ChangeEvent<HTMLInputElement>) => {
setInputValue(event.target.value);
};

const handleOptionClick = (value: string) => {
setInputValue(value);
onSelect(value);
};

const handleKeyDown = (event: React.KeyboardEvent<HTMLInputElement>) => {
switch (event.key) {
case 'ArrowUp':
event.preventDefault();
setActiveIndex((prevIndex) =>
prevIndex > 0 ? prevIndex - 1 : filteredOptions.length - 1
);
break;
case 'ArrowDown':
event.preventDefault();
setActiveIndex((prevIndex) =>
prevIndex < filteredOptions.length - 1 ? prevIndex + 1 : 0
);
break;
case 'Enter':
event.preventDefault();
if (activeIndex !== -1) {
const value = filteredOptions[activeIndex];
setInputValue(value);
onSelect(value);
}
break;
case 'Escape':
event.preventDefault();
setInputValue('');
break;
}
};

return (
<div className={styles.container}>
<input
type="text"
placeholder="Search..."
value={inputValue}
onChange={handleInputChange}
onKeyDown={handleKeyDown}
ref={inputRef}
className={styles.input}
/>
{filteredOptions.length > 0 && (
<ul className={styles.list}>
{filteredOptions.map((option, index) => (
<li
key={option}
className={`${styles.option} ${
index === activeIndex ? styles.active : ''
}`}
onClick={() => handleOptionClick(option)}
>
{option}
</li>
))}
</ul>
)}
</div>
);
};

export default Autocomplete;


Autocomplete.module.css
.container {
position: relative;
display: inline-block;
}

.input {
padding: 5px;
border: 1px solid #ccc;
width: 200px;
font-size: 16px;
}

.list {
position: absolute;
top: 100%;
left: 0;