Techumber

Custom React Dropdown component

Github avatar
January 23, 2022.3 min read

As simple dropdown menu input.

Closed State

20221006014625

Open State

20221006014816

Dropdown.tsx

import * as React from 'react'; import './styles.css'; import CloseIcon from './CloseIcon'; import ArrowIcon from './ArrowIcon'; interface Option { id: number; text: string; } export interface Props { options: Option[]; onSelect?: (opt: Option) => void; onClear?: () => void; } const Dropdown: React.FC<Props> = React.memo( ({ options, onSelect, onClear }) => { const [selectedOption, setSelectedOption] = React.useState(null); const [hideDropdown, setHideDropdown] = React.useState(false); const [filteredOptions, setFilteredOptions] = React.useState([...options]); React.useEffect(() => { setFilteredOptions(options); }, options); const handleItemClick = (opt: Option) => { setSelectedOption(opt); onSelect(opt); }; const handleClear = () => { setSelectedOption({ text: '' }); onClear(); }; const handleInputChange = (e) => { const val = e.target.value; setFilteredOptions( options.filter((opt) => opt.text.toLowerCase().includes(val.toLowerCase()) ) ); }; return ( <div className="dropdown"> <div className="input"> <input value={selectedOption?.text} type="text" onChange={handleInputChange} onFocus={() => setHideDropdown(true)} onBlur={() => setTimeout(() => setHideDropdown(false), 200)} /> {selectedOption?.text ? ( <button className="clear-btn" onClick={handleClear}> <CloseIcon /> </button> ) : null} <div className={!hideDropdown ? 'arrow' : 'arrow-up'}> <ArrowIcon /> </div> </div> {hideDropdown && ( <ul className="dropdown-menu"> {filteredOptions.map((opt) => ( <li className={`menu-item ${ selectedOption?.id === opt.id ? 'slected' : '' }`} key={opt.id} onClick={() => handleItemClick(opt)} > {opt.text} </li> ))} </ul> )} </div> ); } ); export default Dropdown;
  1. Render input box and list items.
  2. Filter by searching for a string.
  3. Click on clear to clear previously selected value.

styles.css

@import url(https://fonts.googleapis.com/css?family=Poppins); body { font-family: 'Poppins', serif; } :root { --color-primary-blue: #00abfa; --color-border-grey: #cacbce; --color-item-hover-background: #f2f2f3; --size-input-border-radius: 12px; --size-input-input-height: 52px; --size-input-padding-x: 16px; } /*This is will work on in webkit browsers*/ ::-webkit-scrollbar { width: 0px; } .dropdown { width: 100%; max-width: 500px; height: 100px; } .input { width: 100%; border: 1px solid var(--color-border-grey); border-radius: var(--size-input-border-radius); overflow: hidden; padding: 0 var(--size-input-padding-x); box-sizing: border-box; display: flex; align-items: center; height: var(--size-input-input-height); } .input:focus-within { border: 1px solid var(--color-primary-blue); } .input input { border: 0; width: 100%; height: 100%; padding: 0; margin: 0; font-size: 18px; } .input input:focus { border: 0; outline: none; } .dropdown-menu { box-shadow: 0px 0px 4px rgba(24, 25, 27, 0.3), 0px 1px 6px rgba(24, 25, 27, 0.15); border-radius: var(--size-input-border-radius); height: 200px; overflow-y: scroll; } .menu-item { font-size: 18px; padding: 15px 10px; } .menu-item.slected { color: var(--color-primary-blue); } .menu-item:hover { cursor: pointer; background-color: var(--color-item-hover-background); } .clear-btn { cursor: pointer; border: 0; background: none; padding: 0; line-height: 0px; } .arrow-up { rotate: 180deg; margin-top: -5px; } .hidden { display: none; }

How to use it?

<Dropdown options={[{id: 'id', text: 'text'}]} onSelect={handleSelect} onClear={handleClear}>

...