Created
November 20, 2023 08:48
-
-
Save Seeyko/cd35dc5c1741600412d4cf6b5da89bcc to your computer and use it in GitHub Desktop.
React Autocomplete, with tailwind and daisyui
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import React, { useState } from 'react'; | |
| const noOptionTitle = "No option !"; | |
| const Autocomplete = ({ options, name }: { options: string[], name: string }) => { | |
| const [activeOption, setActiveOption] = useState(0); | |
| const [filteredOptions, setFilteredOptions] = useState(options); | |
| const [showOptions, setShowOptions] = useState(false); | |
| const [userInput, setUserInput] = useState(''); | |
| const onChange = (e: any) => { | |
| const userInput = e.currentTarget.value; | |
| const filteredOptions: string[] = options.filter( | |
| (option: string) => option.toLowerCase().indexOf(userInput.toLowerCase()) > -1 | |
| ); | |
| setActiveOption(0); | |
| setFilteredOptions(filteredOptions); | |
| setShowOptions(true); | |
| setUserInput(userInput); | |
| }; | |
| const onClick = (e: any) => { | |
| const selectedOption = e.currentTarget.innerText; | |
| setFilteredOptions([selectedOption]); | |
| setActiveOption(0); | |
| setShowOptions(false); | |
| setUserInput(selectedOption); | |
| }; | |
| const onKeyDown = (e: any) => { | |
| if (e.keyCode === 13) { | |
| setShowOptions(false); | |
| const selectedOption = filteredOptions[activeOption]; | |
| setFilteredOptions([selectedOption]); | |
| setActiveOption(0); | |
| setUserInput(selectedOption); | |
| } else if (e.keyCode === 38) { | |
| if (activeOption === 0) { | |
| return; | |
| } | |
| setActiveOption(activeOption - 1); | |
| } else if (e.keyCode === 40) { | |
| if (activeOption - 1 === filteredOptions.length) { | |
| return; | |
| } | |
| setActiveOption(activeOption + 1); | |
| } | |
| }; | |
| let optionList; | |
| if (showOptions) { | |
| if (filteredOptions.length) { | |
| optionList = ( | |
| <ul tabIndex={0} className="menu dropdown-content p-2 shadow-2xl bg-base-100 rounded-box w-full z-[1]"> | |
| {filteredOptions.map((option, index) => { | |
| let className = index === activeOption ? 'bg-base-200' : ''; | |
| return ( | |
| <li key={option} onClick={(e) => onClick(e)}> | |
| <a className={`${className} p-2 pointer-event-none`}>{option}</a> | |
| </li> | |
| ); | |
| })} | |
| </ul> | |
| ); | |
| } else { | |
| optionList = ( | |
| <div className="dropdown-content p-2 shadow-2xl bg-base-100 rounded-box w-full z-10"> | |
| <div className="p-2">{noOptionTitle}</div> | |
| </div> | |
| ); | |
| } | |
| } | |
| return ( | |
| <React.Fragment> | |
| <div className="dropdown"> | |
| <input | |
| type="text" | |
| name={name} | |
| className="input input-bordered w-full pr-8" | |
| onChange={onChange} | |
| onKeyDown={onKeyDown} | |
| onClick={() => setShowOptions(true)} | |
| value={userInput} | |
| ></input> | |
| <div className='absolute right-2 top-3 hover:cursor-pointer pointer-events-none'> | |
| <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"> | |
| <path d="M20 9L14.1213 14.8787C12.9498 16.0503 11.0503 16.0503 9.8787 14.8787L4 9" stroke="black" | |
| stroke-linecap="round" stroke-linejoin="round" /> | |
| </svg> | |
| </div> | |
| {optionList} | |
| </div> | |
| </React.Fragment> | |
| ); | |
| }; | |
| export default Autocomplete; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment