Tips for boosting the tabindex in a React search result list with ul-li elements

Implementing search results using ul li:

<ul className="search-result">
  <li tabindex="1">title here...</li>
  <li tabindex="2">title here...</li>
  <li tabindex="3">title here...</li>
.
.
.
</ul>

Styling for each item:

.search-result{
 li:active, li:focuse {
  font-weight: bold;
  background: #f0f0f0;
 }
}

Now, I'm looking to enhance user experience by allowing navigation between result items using keyboard arrow keys rather than the tab button. How can I access the current active tabindex in the document with JavaScript and increment or decrement it accordingly?

Answer №1

Would you like to use the tab key to navigate through each <li> (search result) and use the up/down arrow keys to move around the list?

Cautiously consider using positive values for tabindex. It's generally best to stick with the default browser focus order, which is based on DOM order. In this scenario, if you want users to tab through each <li> in sequence, there's no need to assign a positive value to tabindex, as the elements are already arranged in the desired tabbing order. Simply set them all to 0.

<ul className="search-result">
  <li tabindex="0">title here...</li>
  <li tabindex="0">title here...</li>
  <li tabindex="0">title here...</li>
.
.
.
</ul>

In general, only interactive elements should have tabindex="0". Since an <li> is not typically interactive, it could confuse users if they tabbed to it without being able to interact. Ask yourself: what can the user do once they reach the <li>? If there's no interaction possible, it shouldn't be a tab stop.

Usually, <li> elements contain interactive content like links or buttons, which are already tab stops by default and don't require a tabindex.

Regarding navigation with the up/down arrow keys, these keys should ideally only move focus between interactive elements. I usually implement an onkeydown event handler on the <ul> element to manage arrow key functionality, adjusting tabindex as needed for each item in the list. However, this approach is suitable when the entire list functions as one tab stop and users must navigate between items using the arrow keys. If your requirements include both behaviors, further clarification may be necessary.

If the list is treated as one tab stop, all <li> elements except the focused one will have tabindex="-1". The focused element will retain tabindex="0", enabling users to tab to the list as a whole and automatically focus on the previously selected item. This setup facilitates seamless up/down traversal of the list.

To handle up/down key presses, simply update the tabindex attribute from 0 to -1 for the currently targeted list item, change the attribute from -1 to 0 for the next item, and utilize focus() to switch focus to the newly selected element.

Answer №2

To keep track of the current tab index, store it in the state and make sure to update it within the keydown eventListener.

import "./styles.css";
import { useState, useEffect } from "react";
import users from "./data";

export default function App() {
  const [searchValue, setSearchValue] = useState("");
  const [currentTab, setCurrentTab] = useState(0);
  const searchResults = users.filter(
    (user) => searchValue.trim() && user.includes(searchValue.trim())
  );
  useEffect(() => {
    const handleKeyDown = (e) => {
      const keyCode = e.keyCode;
      if (keyCode == 38 && searchResults.length - 1 > currentTab)
        setCurrentTab(currentTab + 1);
      if (keyCode == 40 && currentTab >= 1) setCurrentTab(currentTab - 1);
    };
    window.addEventListener("keydown", handleKeyDown);
    return () => window.removeEventListener("keydown", handleKeyDown);
  }, [searchResults, currentTab]);
  return (
    <div>
      <input
        type="text"
        value={searchValue}
        onChange={(e) => {
          setSearchValue(e.target.value);
          setCurrentTab(0);
        }}
      />
      <ul className="search-result">
        {searchResults.map((result, i) => (
          <li className={currentTab === i ? "active" : ""}>{result}</li>
        ))}
      </ul>
    </div>
  );
}

I created a sandbox, feel free to explore!

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

transferring data to Amazon Web Services using Angular framework

I'm currently facing an issue while trying to send a file to an AWS server using an Angular dropzone. I have my AWS credentials ready, but I am unsure of how to properly make the request. Every time I attempt to drop the file into the dropzone, I kee ...

Utilizing VueJS and Lodash: The technique for extracting an array of objects exclusively featuring a specific key string

I am attempting to extract certain data from an Object that has a string _new attached to it. Explore the code on Codesandbox: https://codesandbox.io/s/vibrant-bardeen-77so1u?file=/src/components/Lodash.vue:0-353 This is what my data looks like: data.j ...

Deleting occurrences of a specific text from a JSON document and subsequently analyzing its contents

I am having an issue with a JSON file in which there are strings of characters attached to many of the field names. This is making it difficult for me to target those objects in JS. The structure looks like this: "bk:ParentField": { "bk:Field": "Va ...

Creating a JavaScript and C# popup for deleting records in asp.net

I'm struggling a bit with understanding how server-side deletion works. I know how to use MessageBox, but it's not the best approach. I've been advised to use a popup on the server side. What I'm trying to achieve is that when you clic ...

Utilizing FullCalendar for showcasing comprehensive details

I'm a big fan of the fullcalendar plugin and all its amazing features. I want to enhance it by displaying more customized information for each event when in agendaWeek or agendaMonth view. Switching between views is easy, but I need help filtering out ...

Converting Three.js objects into arrays

I am new to Three.js and I want to add my 'palmtree' object to an array. I believe my code is correct, but something seems off. Here is the snippet of my code: var objects = []; var mtlLoader = new THREE.MTLLoader(); mtlLoader.load("objects/pal ...

Error: The argument passed to int() must be a string, bytes-like object, or number, not 'NoneType' (Issue when sending HTML input to Python)

#!C:\Users\aan\AppData\Local\Programs\Python\Python39\python.exe import numpy as np import skfuzzy as fuzz import cgi from skfuzzy import control as ctrl print("Content-type:text/html\r\n\r\n ...

Easily resolving conflicts by removing `package-lock.json`

Whenever I work in a team environment, I often encounter merge conflicts with the package-lock.json file. My usual solution is to simply delete the file and generate it again using npm install. So far, I haven't noticed any negative effects from this ...

Difficulty encountered while setting up jQuery slider

I am struggling to set up a jquery slider (flexslider) It seems like I am overlooking something very fundamental, but for some reason I just can't figure it out. Any assistance would be greatly appreciated. Please check out the link to the test site ...

What could be the reason for my React/HTML select element occasionally failing to display the default selected value?

I am currently working on creating a select element in Reactjs/HTML and I am facing an issue with setting a default value based on a component variable. Essentially, the default value of the select should be the id of a component. This is my current imple ...

Which design pattern would be best suited for monitoring the completion of multiple ajax requests?

In my code, I have combined 3 separate ajax calls in one function along with checkAjaxCompletion method to monitor each ajax completion flag. The current approach involves sending multiple independent ajax calls and using an interval method to continuousl ...

Inject a heavy dose of Vue into your project

**I'm trying to implement the provide/inject logic in Vue. In my 'App.vue' component, I have defined the 'firstName' input as a string "John", and I want to display this value when the child component 'Step1' is created. ...

including a collection of values into a JSON data structure

Currently, I am iterating through some JSON data (grouped tweets from Twitter) to tally the frequency of specific keywords (hashtags) in order to generate an organized list of common terms. this (19) that (9) hat (3) I have achieved this by initial ...

Is there a way to showcase a Bootstrap popover using HTML content sourced from a GridView?

I've spent the last couple of hours experimenting with this, trying different things. I can successfully display a popover with basic title and content, but I'm struggling to make it work with HTML and Eval() as the content. Here's my curren ...

Combine several elements in a single jQuery scrollreveal function

I am currently working on a webpage that utilizes the jQuery library plugin scrollreveal to gradually reveal different html elements when the page loads. The functionality of the code is working correctly at the moment, but I have noticed that there is a d ...

The form will be submitted even if the validation conditions are not met, and the form

I've been struggling to understand why this issue keeps occurring despite hours of unsuccessful research. Here's the code for a registration page that submits the form regardless of the conditions being true or false. I've experimented with ...

Click on a plane within a three.js environment to determine the X Y position within it

When using a raycaster, I can successfully obtain the current object (in this case, a plane) under the mouse. However, I am seeking a more precise X and Y value for the mouse position INSIDE the plane. var vector = new THREE.Vector3( ( event.clientX / win ...

Is it necessary to encode the content before transmitting HTML in JSON from the server to the client?

When it comes to sending HTML content from the server to the client for displaying user comments in a rich JS app that communicates through a JSON API, there are some considerations to keep in mind. One important question is how to handle the content with ...

Database connection error: Authentication protocol requested by server not supported

I have been struggling with the issue outlined in this link: MySQL 8.0 - Client does not support authentication protocol requested by server; consider upgrading MySQL client Even though I have tried following the recommendations, I am still encountering e ...

AngularJS Perspectives: Unveiling the Secrets of Successful Implementation

Do you have any tips on troubleshooting AngularJS views? I found a demo at AngularJS: ngView, but the provided jsfiddle doesn't seem to work. I've been trying to play around with it, but still haven't had any success. This is the code I&apo ...