38

I’m working with basic HTML <input type="text"/> text field with a numeric value.

I’m adding JavaScript event keyup to see when user presses arrow up key (e.which == 38) – then I increment the numeric value.

The code works well, but there’s one thing that bugs me. Both Safari/Mac and Firefox/Mac move cursor at the very beginning when I’m pressing the arrow up key. This is a default behavior for every <input type="text"/> text field as far as I know and it makes sense.

But this creates not a very aesthetic effect of cursor jumping back and forward (after value was altered).

The jump at the beginning happens on keydown but even with this knowledge I’m not able to prevent it from occuring. I tried the following:

input.addEventListener('keydown', function(e) {
    e.preventDefault();
}, false);

Putting e.preventDefault() in keyup event doesn’t help either.

Is there any way to prevent cursor from moving?

riddle
  • 655
  • 1
  • 6
  • 9

6 Answers6

30

To preserve cursor position, backup input.selectionStart before changing value.

The problem is that WebKit reacts to keydown and Opera prefers keypress, so there's kludge: both are handled and throttled.

var ignoreKey = false;
var handler = function(e)
{
    if (ignoreKey)
    {
        e.preventDefault();
        return;
    }
    if (e.keyCode == 38 || e.keyCode == 40) 
    {
        var pos = this.selectionStart;
        this.value = (e.keyCode == 38?1:-1)+parseInt(this.value,10);        
        this.selectionStart = pos; this.selectionEnd = pos;

        ignoreKey = true; setTimeout(function(){ignoreKey=false},1);
        e.preventDefault();
    }
};

input.addEventListener('keydown',handler,false);
input.addEventListener('keypress',handler,false);
Kornel
  • 97,764
  • 37
  • 219
  • 309
18

I found that a better solution is just to return false; to prevent the default arrow key behavior:

input.addEventListener("keydown", function(e) {
    if (e.key === 'ArrowUp' || e.key === 'ArrowDown') return false;
}, false);
Lukas
  • 9,765
  • 2
  • 37
  • 45
  • 1
    Thanks man. The idea is to use the keydown event instead of keyup. – Manish Singh Jan 14 '14 at 09:50
  • 6
    Right - keydown is the trick. Note that returning false seems to stop the event's propagation entirely, whereas `preventDefault()` will let the input box ignore the event, while still allowing other listeners to handle it as it bubbles up. – CmdrMoozy Jun 05 '14 at 17:35
  • 5
    @Lukas , your solution worked best for me. However, I'm calling `e.preventDefault();` instead of returning `false`. The latter didn't achieve the freezing of the up-arrow key behavior. Thanks for posting an alternate, simpler solution. – Mario J Vargas Jun 11 '14 at 20:33
  • 1
    This is the correct answer! I had to use the keydown event to stop the cursor moving and then the keyup event to get the input value when needed – darylhedley Sep 11 '14 at 14:39
  • Using e.code === 'ArrowUp' || e.code === 'ArrowDown' will make the code is much easier to read. – Nurul Huda Aug 16 '19 at 02:10
  • Perfect solution! Saved me so much time, I'm using Vue and all I had to do is ``. – Robert Kujawa Jun 12 '21 at 14:46
9

Actually, there is a better and simpler method to do this job.

$('input').bind('keydown', function(e){
    if(e.keyCode == '38' || e.keyCode == '40'){
        e.preventDefault();
    }
});

Yes, it is so easy!

JChen___
  • 3,593
  • 2
  • 20
  • 12
1

In my case (react) helped:

onKeyDown = {
  (e) => {
    if (e.key === 'ArrowUp' || e.key === 'ArrowDown') e.preventDefault();
  }
}

and onKeyUp was fully functional

Prathamesh More
  • 1,470
  • 2
  • 18
  • 32
0

I tested the code and it seems that it cancels the event but if you don't press the arrow for very short time - it fires keypress event and that event actually moves cursor. Just use preventDefault() also in keypress event handler and it should be fine.

  • Unfortunately, `e.preventDefault()` in `keypress` event prevents me from entering anything there (I want inputs to work like in Firebug). And it doesn’t solve my problem, at least in my browser – cursor still jumps at the very beginning. – riddle Jul 03 '09 at 19:56
-2

Probably not. You should instead seek for a solution to move the cursor back to the end of the field where it was. The effect would be the same for the user since it is too quick to be perceived by a human.

I googled some and found this piece of code. I can't test it now and it is said to not to work on IE 6.

textBox.setSelectionRange(textBox.value.length, textBox.value.length);

Leahn Novash
  • 2,861
  • 2
  • 20
  • 18
  • 1
    Thanks. Actually updating input.value will result in cursor moving back at the end. So I might detect cursor’s position and then restore it after change is made (if it’s in the middle of number, for example). But I’m still looking for better solution, if it’s available. – riddle Jul 03 '09 at 19:29