Trap focus using javaScript
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: cdn.hashnode.com/res/hashnode/image/upload/..
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
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
- Creating some input fields on the page for the demo:
<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>
- Writing some CSS to make this ugly page a little beautiful because why not :wink:
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-
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-
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-
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-
//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-
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-
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-
// 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-
DONE!! you've done it. Check out this codepen to see it live-
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...