Kay Lamerigts
Kay Lamerigts

Reputation: 722

Shift focus with arrow keys in JavaScript

I want to be able to navigate through all the focusable elements on my webpage with the arrow key. So when the down-key is pressed the focus should shift to the focusable element beneath the current focussed element. You get the idea for the other arrow keys, when there is not a focusable element to shift to, the focus should remain the same.

This is what I got so far:

$(document).keydown(function(e){    

if (e.keyCode == 37) { //left

   var offset = $("*:focus").offset();

   var allElements = $("#container").find('a[href], area[href], input:not([disabled]), select:not([disabled]), textarea:not([disabled]), button:not([disabled]), iframe, object, embed, *[tabindex], *[contenteditable]');

   var arr = jQuery.makeArray(allElements);

   var topLeft = offset.left
   var minus = topLeft;
   var currentElement = $("*:focus");

   for(var i = 0; i < arr.length; i++)
   {

      if ( (arr[i].offset().left < offset.left)  // This doesn't work for some reason
        && ((offset.left - arr[i].offset().left) < minus))
      {
        currentElement = arr[i];
        minus = offset.left - arr[i].offset().left;
        topLeft = arr[i].offset().left;
      }


      currentElement.focus();
   }


   alert( "left pressed" );
   return false;
}

// Other Keys

});

the idea was to get all the focus-able elements and than pick select the one that is suited for the arrow and shift focus.

I'm not able to get this code to work (it contains a error) and I'm not completly sure it will even work.

Thnx in advance

[EDIT]: I guess I was a little vague. I do not only want to go left and right, but also up and down.

Upvotes: 16

Views: 50191

Answers (6)

baron_bartek
baron_bartek

Reputation: 1127

None of above solutions worked for me. This one is mine. It look difficult but it's accually real easy. Create array of link and change focus using the array index. (I needed up/down arrow so keycodes are different). It also works with dynamicly added links (cause I needed it this way, that is why I use on)

$('#links_container').on("keydown", ".link",
    function(e)
    {    

        //start - list of <a>
        var flag = false;
        var smallMeni = document.getElementById('links_container');
        var allElements2 = smallMeni.getElementsByTagName('a'); //.link
        //end

        //start - key down
        if (e.keyCode == 40) 
        {           
            for (var i=0;i<allElements2.length;i++)
            {

                if(flag == true){

                    flag = false

                    allElements2[i].focus();

                    //alert(i)
                }
                else
                {
                    if ( document.activeElement === allElements2[i] )
                    {
                        //alert(i);
                        flag = true;
                    }           
                }

            }
        }
        //end

        //start - key up
        if (e.keyCode == 38) 
        {           
            for (var i=0;i<allElements2.length;i++)
            {

                if ( document.activeElement === allElements2[i] )
                {
                    if (i>0)
                    {
                        allElements2[i-1].focus();                  
                    }
                }           

            }
        }           

        //alert(i);

    }
);

Upvotes: 0

Axel EsZu
Axel EsZu

Reputation: 41

This works great

$('p').each(function(index) {
  $(this).attr('tabindex', index)
}).on('keyup', function(e) {
  e.preventDefault;
  if (e.keyCode == 39) {
    $('[TabIndex="' + Number(Number($(this).attr('tabindex')) + 1) + '"]').focus();
  }
  if (e.keyCode == 37) {
    $('[TabIndex="' + Number(Number($(this).attr('tabindex')) - 1) + '"]').focus();
  }
});

Upvotes: 0

Ahmad Shakil
Ahmad Shakil

Reputation: 11

Implemented above by checking some articles and stack over flow links

jQuery.fn.elementAfter = function(other) {
for(i = 0; i < this.length - 1; i++) {
    if (this[i] == other) {
        return jQuery(this[i + 1]);
    }
}
return jQuery;
} ;

jQuery.fn.elementBefore = function(other) {
if (this.length > 0) {               
    for(i = 1; i < this.length; i++) {
        if (this[i] == other) {
            return jQuery(this[i - 1]);
        }
    }
}
return jQuery;
};

https://jsfiddle.net/bkLnq5js/79/

Upvotes: 0

Cranio
Cranio

Reputation: 9847

What I would do is much simpler. Just add a common class among the objects who should have this functionality (f.ex. "move") and use:

$(document).keydown(
    function(e)
    {    
        if (e.keyCode == 39) {      
            $(".move:focus").next().focus();

        }
        if (e.keyCode == 37) {      
            $(".move:focus").prev().focus();

        }
    }
);
​

See example: http://jsfiddle.net/uJ4PJ/

This code is much simpler and hopefully has all the functionality you need.

Just make sure the controls are in the correct order or this won't work properly.

Upvotes: 33

user2462210
user2462210

Reputation: 39

After much trial and error, I developed this code that works :

function navigate(origin, sens) {
    var inputs = $('#form').find('input:enabled');
    var index = inputs.index(origin);
    index += sens;
    if (index < 0) {
        index = inputs.length - 1;
    }
    if (index > inputs.length - 1) {
        index = 0;
    }
    inputs.eq(index).focus();
}

$('input').keydown(function(e) {
    if (e.keyCode==37) {
        navigate(e.target, -1);
    }
    if (e.keyCode==39) {
        navigate(e.target, 1);
    }
});

right arrow acts as tab

left arrow acts as shift tab

Upvotes: 3

Jānis
Jānis

Reputation: 328

Preview - http://jsfiddle.net/FehKh/ ;)

html:

<a href='jqwja' class="focusable">jajaj</a>
<a href='jjaasd' class="focusable focused">jajasdaaj</a>
<a href='jjqwea' class="focusable">jajaacasj</a>
<input value='iddqd' name="DoomII" class="focusable" />​

js:

// init
$('.focused').focus();

// actual code
$(document).keydown(function(e){    
    if (e.keyCode == 37) { // left
        if($('.focused').prev('.focusable').length)
            $('.focused').removeClass('focused').prev('.focusable').focus().addClass('focused');
    }
    if (e.keyCode == 39) { // right
        if($('.focused').next('.focusable').length)
            $('.focused').removeClass('focused').next('.focusable').focus().addClass('focused');
    }
});​

Upvotes: 2

Related Questions