Mathias Bynens

Using the oninput event handler with onkeyup/onkeydown as its fallback

· tagged with DOM, HTML, JavaScript

HTML5 standardizes the oninput event handler, which should be used to detect user input in JavaScript. Sure, you could use onkeydown or onkeyup instead, but those were never really designed for this particular use case, and it shows.

Luckily, all modern browsers support oninput, IE9 included. For older browsers it’s a good idea to fall back to the keydown event, for example. Unfortunately, detecting oninput support isn’t as straight-forward as you’d think. I assumed this JavaScript snippet would return true or false, depending on whether oninput is supported or not:

'oninput' in document.createElement('input');

This works correctly in most browsers, but not in Firefox (see bug #414853). While it’s still possible to write a working feature test for oninput, it’s really cumbersome.

Besides, there’s no need to feature test — just bind handlers to both the input and keydown events, and then remove the onkeydown handler as soon as the oninput handler fires. Here’s a simple example, DOM0-style:

someElement.oninput = function() {
this.onkeydown = null;
// Your code goes here
};
someElement.onkeydown = function() {
// Your code goes here
};

The keydown event will only fire once (since it fires before oninput) – after that, only oninput will be used. That’s not ideal, but it sure beats adding lines and lines of code just to properly detect oninput support in all browsers.

A simple demo is available. Note that the same pattern can be applied for any event handler that has a lesser alternative in older browsers.

Comments

Mathias wrote on :

Of course, since you’re probably re-using the same code in both handlers, you could use a separate function:

function update() {
// Your code goes here, e.g.
console.log(this.value);
}
someElement.oninput = function() {
this.onkeydown = null;
update.call(this);
};
someElement.onkeydown = function() {
update.call(this);
};

If you’re using jQuery events, you could use jQuery#unbind:

function update() {
// Your code goes here, e.g.
console.log(this.value);
}
var $someElement = $(someElement);
$someElement.bind({
'input': function() {
$someElement.unbind('keydown');
update.call(this);
},
'keydown': update
});

Here’s a quick jQuery plugin (GitHub repository):

$.fn.input = function(fn) {
var $this = this;
if (!fn) {
return $this.trigger('keydown.input');
}
return $this.bind({
'input.input': function(event) {
$this.unbind('keydown.input');
fn.call(this, event);
},
'keydown.input': function(event) {
fn.call(this, event);
}
});
};

Use it as follows:

$('.any-number-of-elements').input(function(event) {
alert(this.value);
event.preventDefault();
});

Note that namespaced events are used to prevent unbinding other jQuery-bound keydown event handlers. Also, in addition to keydown, you could bind to the cut, paste and drop events as well.

Zoltan Hawryluk wrote on :

Great idea doing the double oninput/onkeydown trick! Coincidentally, I was also doing some research on oninput as well. IE9 has a really annoying bug where backspace and delete (as well as cutting parts out of the input element) were not firing the oninput event. :-( I hope you forgive the shameless self-promotion, but I wrote an article about how to fix this problem, and how I updated my HTML5 forms polyfill, html5Widgets to fix these issues as well as add support in older IEs.

Note that this only fixes it in the <form> element, which I find the most useful since it will fire the oninput event when any value in any input of the form is modified. I am going to do more research before I fix it for all the others, since I want to research other issues before I support more tags (the Firefox bug you state above may be one of them).

Andy Earnshaw wrote on :

I’ve found that onpropertychange will give results similar to oninput, so when not using jQuery (which I have a plugin for), I use the following code:

if (!("oninput" in document.body)) {
element.onpropertychange = function() {
if (event.propertyName == "value")
this.oninput && this.oninput(event);
}
}
element.oninput = function() {
// …
}

Since Firefox and other browsers have supported oninput for a while, I decided that detection isn’t really necessary. I would say that I get more IE 6 users on my sites than Firefox 1 or Opera 8 :-) For the ultra paranoid, it would be easy to combine your code with mine and have IE 5.5+ working just as good as Chrome 11, with the fallback in place just in case a visitor happens to be using Opera 8.

Tim Down wrote on :

One annoyance is that Safari prior to version 5 doesn’t support the input event for textareas. It does however support a textinput event instead.

Leave a comment

Comment on “Using the oninput event handler with onkeyup/onkeydown as its fallback”

Some Markdown is allowed; HTML isn’t. Keyboard shortcuts are available.

It’s possible to add emphasis to text:

_Emphasize_ some terms. Perhaps you’d rather use **strong emphasis** instead?

Select some text and press + I on Mac or Ctrl + I on Windows to make it italic. For bold text, use + B or Ctrl + B.

To create links:

Here’s an inline link to [Google](http://www.google.com/).

If the link itself is not descriptive enough to tell users where they’re going, you might want to create a link with a title attribute, which will show up on hover:

Here’s a [poorly-named link](http://www.google.com/ "Google").

Use backticks (`) to create an inline <code> span:

In HTML, the `p` element represents a paragraph.

Select some inline text and press + K on Mac or Ctrl + K on Windows to make it a <code> span.

Indent four spaces to create an escaped <pre><code> block:

    printf("goodbye world!"); /* his suicide note
was in C */

Alternatively, you could use triple backtick syntax:

```
printf("goodbye world!"); /* his suicide note
was in C */
```

Select a block of text (more than one line) and press + K on Mac or Ctrl + K on Windows to make it a preformatted <code> block.

Quoting text can be done as follows:

> Lorem iPad dolor sit amet, consectetur Apple adipisicing elit,
> sed do eiusmod incididunt ut labore et dolore magna aliqua Shenzhen.
> Ut enim ad minim veniam, quis nostrud no multi-tasking ullamco laboris
> nisi ut aliquip iPad ex ea commodo consequat.

Select a block of text and press + E on Mac or Ctrl + E on Windows to make it a <blockquote>.