How to control the list of elements throw keyboard events

59 Views Asked by At

UI image https://stackblitz.com/edit/react-o1ra7c

After the user searches results, the user tries to use keyboard events arrows need to move down.

<div>
            
              
              <input onChange={handleSearchChange}/>
            
            <div css={countryDataCss}>
              {countryList?.map((country) => (
                <div key={country.countryCode}>
                  <span css={countryCss}>{country.countryName}</span>
                  <span css={countryDialCodeCss}>
                    {country.countryDialNo}
                  </span>
                </div>
              ))}
            </div>
          </div>
1

There are 1 best solutions below

0
Naren Murali On BEST ANSWER

You can use the javascirpt event onkeydown which for react is onKeyDown which gives the required behaviour, please check the below stackblitz!

import React from 'react';
import './style.css';
import { useState } from 'react';

export default function App() {
  const [searchText, setSearchText] = useState('');
  const [selectedCountry, setSelectedCountry] = useState('SG');
  const [activeIndex, setActiveIndex] = useState(0);
  const [selectedDialCode, setSelectedDialCode] = useState('+65');
  const countryCodeListResponse = [
    { countryCode: 'IND', countryDialNo: '+91', countryName: 'India' },
    { countryCode: 'SG', countryDialNo: '+65', countryName: 'Singpare' },
  ];
  const [countryList, setCountryList] = useState(countryCodeListResponse);
  function handleSearchChange(e) {
    const searchText = e.target.value.toLowerCase();

    if (countryCodeListResponse) {
      const updatedList = countryCodeListResponse
        .filter((el) => el.countryName.toLowerCase().includes(searchText))
        .sort(
          (a, b) =>
            a.countryName.toLowerCase().indexOf(searchText) -
            b.countryName.toLowerCase().indexOf(searchText)
        );

      setSearchText(searchText);
      setCountryList(updatedList);
    }
  }

  const onSelectCountry = (code, dialCode) => {
    setSelectedCountry(code);
    setSelectedDialCode(dialCode);
    setSearchText('');
    setCountryList(countryCodeListResponse);
  };

  const onKeyDown = (event) => {
    console.log(event);
    switch (event.keyCode) {
      case 38: // arrow up
        if (activeIndex > 0 && activeIndex <= countryList.length - 1) {
          setActiveIndex((prev) => prev - 1);
        }
        break;
      case 40: // arrow down
        if (activeIndex >= 0 && activeIndex < countryList.length - 1) {
          setActiveIndex((prev) => prev + 1);
        }
        break;
      case 13:
        const country = countryList[activeIndex];
        onSelectCountry(country.countryCode, country.countryDialNo);
        break;
      default:
        break;
    }
  };

  return (
    <div class="dropdown">
      <div class="search">
        <div>
          <span>{selectedCountry}</span>
          <span>{selectedDialCode}</span>
        </div>
        <input
          class="search-input"
          onKeyDown={(e) => onKeyDown(e)}
          placeholder="Search"
          value={searchText}
          onChange={handleSearchChange}
        />
      </div>
      <div class="list">
        {countryList?.map((country, index) => (
          <div
            onKeyDown={(e) => onKeyDown(e)}
            className={index === activeIndex ? 'active' : ''}
            tabIndex="0"
            key={country.countryCode}
            onClick={() =>
              onSelectCountry(country.countryCode, country.countryDialNo)
            }
          >
            <span>{country.countryName}</span>
            <span>{country.countryDialNo}</span>
          </div>
        ))}
      </div>
    </div>
  );
}

stackblitz