Home > Blockchain >  Javascript to shift focus from input to list item links with keyboard arrow keys, the same as TAB ke
Javascript to shift focus from input to list item links with keyboard arrow keys, the same as TAB ke

Time:08-12

I have the following input and list:

<input id="myinput" type="text">

<ul id="mylist">
    <li ><a href="#">Link 1</a></li>
    <li ><a href="#">Link 2</a></li>
    <li ><a href="#">Link 3</a></li>
    <li ><a href="#">Link 4</a></li>
    <li ><a href="#">Link 5</a></li>
</ul>

with the following css to show/hide certain list items:

.display {
  display: block;
}
.hide {
  display: none;
}

I'm looking for javascript (preferably vanilla) so that when the user's cursor is inside the input, the keyboard's down arrow would shift focus from the input to the first displayed list items or links (in this case Link 2, 4 and 5). In other words, the same way the tab key works by default.

Then the up/down arrow keys could be used to continue to shift focus to the next/previous displayed list items/links or back up to the input.

JSFiddle

Thanks!

CodePudding user response:

You can add a keydown listener. Then check if the element that currently has focus is either the input or one of the <a>s in the list. Then move focus according to the key that was pressed.

Note that the browser does not necessarily apply focus-visible when focus is applied pragmatically. So in order to see the focus we need to add styles to the :focus pseudo-class.

Here's is a snippet with the above.

document.addEventListener('keydown', e => {
  if (e.key !== 'ArrowUp' && e.key !== 'ArrowDown') return;
  const focusElem = document.querySelector(':focus');
  const tabElements = [...document.querySelectorAll('#myinput, #mylist>li.display>a')];
  const tabElementsCount = tabElements.length - 1;
  if (!tabElements.includes(focusElem)) return;
  e.preventDefault();
  const focusIndex = tabElements.indexOf(focusElem);
  let elemToFocus;
  if (e.key === 'ArrowUp') elemToFocus = tabElements[focusIndex > 0 ? focusIndex - 1 : tabElementsCount];
  if (e.key === 'ArrowDown') elemToFocus = tabElements[focusIndex < tabElementsCount ? focusIndex   1 : 0];
  elemToFocus.focus();
});
.hide {
  display: none;
}

:focus {
  outline: solid 2px #000;
}
<input id="myinput" type="text">
<ul id="mylist">
  <li ><a href="#">Link 1</a></li>
  <li ><a href="#">Link 2</a></li>
  <li ><a href="#">Link 3</a></li>
  <li ><a href="#">Link 4</a></li>
  <li ><a href="#">Link 5</a></li>
</ul>

  • Related