Trap focus using javaScript
Tags: webdev, javascript, htmlfocus, eventlistener
Published: 2020-01-20 13:04:03

---
title: Trap focus using javaScript
published: true
description: Setting up custom keys to focus previous/next element in the tab index
tags: Web Development,JavaScript,HTML focus,Event Listener, 
cover_image: https://thepracticaldev.s3.amazonaws.com/i/v9nv6c0gha58d2vlmuqo.gif
---

### Setting up custom keys to focus previous/next element in the tab index 

#### Introduction

On a web page, we have different focusable elements and they follow a default tab order. We can navigate around and change focus from one focusable element to another using `Tab` and `Shift + Tab` keys. 

You can easily check this behavior on any website. Just press `Tab` to move your focus to the next focusable element and press `Shift + Tab` for the previous one. 

We can manipulate this default Tab flow and create our own flow using `tabindex` but this is not the focus of this article. We want to use a custom key to change the focus just like we use `Tab` and `Shift + Tab` keys.

In this article, we will learn how to trap the browser focus using javaScript and assign it to `UP` and `DOWN` arrow keys to focus the next and the previous focusable elements (`input box` in our example) 


#### What we are going to build


![Demo page](https://thepracticaldev.s3.amazonaws.com/i/63cejvita7y74gqkeq7t.png)


We are going to create a web page having some input fields. We will create a function that will listen to the `keypress event` and change the focus of the element on pressing arrow UP and DOWN keys.

Let's begin-

## Setup

1. Creating some input fields on the page for the demo:



``` html
<div class="container">
    <h1 class="text-center">Trap focus using javaScript</h1>
    <div class="input-wrapper">
      <input type="text" placeholder="Input 1" value="">
      <input type="text" placeholder="Input 2" value="">
      <input type="text" placeholder="Input 3" value="">
      <input type="text" placeholder="Input 4" value="">
      <input type="text" placeholder="Input 5" value="">
      <button>Submit</button>
    </div>
  </div>
```

2. Writing some CSS to make this ugly page a little beautiful because why not :wink:

``` css

html{
  background: black;
}

.container{
  background: yellow;
  width: 100%;
  max-width: 500px;
  margin: auto;
  border-radius: 10px;
}

h1{
  padding-top: 0.4em;
}

.input-wrapper{
  background: pink;
  padding: 1em;
  display: flex;
  flex-direction: column;
  border-radius: 0 0 10px 10px;
}

.input-wrapper input{
  margin: 0.4em auto;
  padding: 0.4em;
  font-size: 1.4em;
  width: 400px
}

.text-center{
  text-align: center;
}

button{
  width: 100px;
  padding: 0.4em;
  border-radius: 4px;
  margin: auto;
  font-size: 1.2em;
  cursor: pointer;
}

```

## The JavaScript part 

We know that the browser fires `DOM events` on various kinds of events (of course) happening on the page. 

We are going to listen to `keydown` events on the input fields so that whenever the user press UP or DOWN keys we will change the focus on the page to previous or the next element respectively.

Now here's a question, why I chose `keydown` event for this and not `keypress`. The answer is compatibility with different browsers. Since I'll be using `event.keyCode` in this example, I found using `keydown` or `keyup` instead of `keypress` events will work in every major browser.


Alright enough talking, let's get to the coding part-


let's begin with creating a function which we will invoke on `keydown` event in the browser- 

```js
function handleInputFocusTransfer(e){
// we will write code for the functionality here...
}
```

Now inside this function, we will write the logic for changing the focus on the page.

let's create a variable to store the reference of all the focusable elements we want to use. 
In our example, we are manipulating focus for input fields but you can use any elements on the page and select them in the same way-

```js
const focusableInputElements= document.querySelectorAll(`input`);
```

`document.querySelectorAll` will return a node list. we will create an array from this node list using spread operator as follow-

```js
  const focusable= [...focusableInputElements]; 
```

At this point, we have an array `focusable` of all the focusable elements on the page. The current element which is in focus on the page is also present in this array. So, let's find at which index this guy is sitting-

```js
 //get the index of current item in the "focusable" array
  const index = focusable.indexOf(document.activeElement); 
```
Here, `document.activeElement` returns the active node element on the page.

Let's also create a variable to store the index of the next element to be focussed-

```js
  let nextIndex = 0;
```
I have initialized it with 0 but later we will change it on UP or DOWN arrow key press accordingly.

Now, on `keyDown` event, the event object has an entry `keyCode` which stores the ASCII (RFC 20) or Windows 1252 code corresponding to the pressed key.

It is 38 and 40 for the UP and DOWN arrow keys respectively.

Next, we will write a if-else statement which will change the value of `nextIndex` according to which key was pressed-

```js
  if (e.keyCode === 38) {
    // up arrow
    e.preventDefault();
    nextIndex= index > 0 ? index-1 : 0;
    focusableInputElements[nextIndex].focus();
  }
  else if (e.keyCode === 40) {
    // down arrow
    e.preventDefault();
    nextIndex= index+1 < focusable.length ? index+1 : index;
    focusableInputElements[nextIndex].focus();
  }
```

In the if-block above, if the keyCode is 38 (i.e UP arrow key) we are decreasing the value of `index` by 1 so that just the previous focusable element in the `focusableInputElements` array can be focussed using `focus()` method provided by the DOM API.

Similarly, in the else-block, we are increasing the value of `index` by 1 to focus on the next focusable element.

You'll see I have also taken care of boundary conditions using a ternary operator. This is just to make sure that `nextIndex` always holds a positive value smaller than the size of the `focusableInputElements` array to avoid errors.

That's all. Now put these code together inside our `handleInputFocusTransfer` function and set up an event listener for `keydown` event on the page.

The whole javascript code now looks like this-

``` js

// Adding event listener on the page-
document.addEventListener('keydown',handleInputFocusTransfer);

function handleInputFocusTransfer(e){

  const focusableInputElements= document.querySelectorAll(`input`);
  
  //Creating an array from the node list
  const focusable= [...focusableInputElements]; 
  
  //get the index of current item
  const index = focusable.indexOf(document.activeElement); 
  
  // Create a variable to store the idex of next item to be focussed
  let nextIndex = 0;

  if (e.keyCode === 38) {
    // up arrow
    e.preventDefault();
    nextIndex= index > 0 ? index-1 : 0;
    focusableInputElements[nextIndex].focus();
  }
  else if (e.keyCode === 40) {
    // down arrow
    e.preventDefault();
    nextIndex= index+1 < focusable.length ? index+1 : index;
    focusableInputElements[nextIndex].focus();
  }
}

```

Now our web page looks like this. Note how the focus is changing on pressing UP and DOWN arrow keys-
![Demo page gif](https://thepracticaldev.s3.amazonaws.com/i/v9nv6c0gha58d2vlmuqo.gif)

DONE!! you've done it. Check out this codepen to see it live-

https://codepen.io/ishubhamprakash/pen/OJPagqj


>
This is my first post on dev.to
Hope you'll like it. Smash whatever buttons this platform provides to appreciate the work let me know that you loved this post  :smile:
>

More posts coming...