Prevent default behavior in text input while pressing arrow up

riddle picture riddle · Jul 3, 2009 · Viewed 36.8k times · Source

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?

Answer

Kornel picture Kornel · Jul 4, 2009

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);