onchange vs. oninput for Range Sliders

on | 7 Comments

A common UI pattern for a range slider is to allow the user to move the slider and display the value of it somewhere on the page, changing the displayed value as the user moves the slider.

I think the expected behaviour in such a case is that the value should display instantly, as the user is moving the slider, rather than the page waiting for the slider to finish moving before the displayed value is updated. I suppose there could be cases where you prefer a delay over instant results, but I think the expected behaviour is to display the results instantly.

As you’ll see in the videos below and in your own testing, the behaviour of the input event compared to the change event is not exactly the same in different browsers when applied to a range slider.

Let’s look at how these events behave in the different browsers. The code I’ll be using is embedded in the JS Bin example below:

JS Bin

Swap change with input to see the differences I’ll be discussing. The results described are observed on OSX and Windows 7.

Note: Opera is equivalent to Chrome in these tests because it now has the same rendering engine.

oninput in Chrome

Observations:

  • Works as expected, the input event fires immediately when the slider is adjusted, which is demonstrated by the value changing on the page instantly.
  • Focusing and adjusting the slider with the keyboard has the same result.

onchange in Chrome

Observations:

  • The change event does not fire immediately, demonstrated by the fact that the value on the page does not change until the slider stops moving.
  • Keyboard interaction, however, is the same as oninput, with the value on the page updating immediately.

oninput in Firefox

Observations:

  • Same results as oninput in Chrome; changes happen immediately.
  • Keyboard results the same, changes appear immediately.

onchange in Firefox

Observations:

  • Same results as Chrome; the value doesn’t change on the page until the slider stops moving.
  • When moving the slider with the keyboard, the value does not update until the slider is blurred, or unfocused. This is the only difference from the behaviour in Chrome.

oninput in IE11

Observations:

  • oninput is not recognized at all when used on a range slider. The same event, however, does fire when used on a text input.
  • Although oninput doesn’t fire, the value of the slider is displayed in a native tooltip, which doesn’t happen on the other browsers.
  • The keyboard likewise has no effect on the value and the native tooltip is not displayed.

onchange in IE11

Observations:

  • Works the same way as oninput in Chrome and Firefox; the value changes immediately while the slider is still moving.
  • Keyboard results are the same, the value updates immediately.

What’s the Correct Behaviour?

The WHATWG spec describes the expected behaviour as follows:

The input event fires whenever the user has modified the data of the control. The change event fires when the value is committed, if that makes sense for the control, or else when the control loses focus. In all cases, the input event comes before the corresponding change event (if any).

The same description is found in the W3C version of the spec.

For oninput, Chrome and Firefox have the correct behaviour with both mouse and keyboard interaction. But Firefox seems to have the most accurate behaviour for onchange.

As shown in the quote above, onchange should always fire after oninput, so the fact that Firefox waits for the range slider to lose focus before firing the event (for both mouse and keyboard) seems to be the correct behaviour. Chrome does not wait until the control is unfocused when using the keyboard, but it does so with the mouse.

IE11, of course, is completely wrong on two counts: It doesn’t recognize oninput when applied to a range slider and it responds to onchange as if it was oninput, firing the event immediately instead of waiting until the slider stops moving or loses focus.

As a side point here, the HTML4 spec seemed to define the behaviour a little more clearly:

The onchange event occurs when a control loses the input focus and its value has been modified since gaining focus.

Though when that was written, there was no such thing as type="range" for form inputs.

Sources and Bug Reports

There has been discussion on this behaviour in the bug trackers for the various browsers, and I believe the wording in the spec was updated to be less ambiguous — although I still feel that it’s not 100% clear if Firefox’s keyboard behaviour is the correct one.

Here are some relevant links in addition to the ones provided in the article above:

  • Firefox bug report – Closed as “invalid” since Firefox’s behaviour is correct.
  • IE11 bug report on missing input event, still unresolved.
  • Chrome bug report which I filed myself to see if the different keyboard behaviour can be corrected to agree with Firefox.
  • W3C bug report, which attempts to make the spec less ambiguous.
  • change event on MDN, which explains that “different browsers do not always agree whether a change event should be fired for certain types of interaction.”

7 Responses

  1. Anders Ringqvist:

    Great research and even greater with movies to show. =)

    If I am not misstaken onchange first appeared on the select element and at first it was instant as oninput is today but designers misused it as navigation menus where users selected an option with some name and a URL as value and location.href was set to that value. So when a keyboard user arrived they couldn’t use the site cause they were being navigated away from the page before they could get passed first option. When this was changed and later standardised there was a great disturbance in the Community, as if millions of designers suddenly cried out in terror and were suddenly forced to accompany all navigation select boxes with a button. Usability has sadly never been prioritised among most designers.

  2. xem:

    I made a few observations about these two events in june on Twitter:
    https://twitter.com/MaximeEuziere/status/478149970881966080
    It’s good to see them described in a real article. Good job!
    M.

  3. Jim Richardson:

    Used this idea with a spin–button control. Works great, updates every value change.

    thank you. I have been trying to solve the update problem for hours.

  4. Thanks for sharing this.
    I was struggling to get Material Design Lite slider values on onChange event. Your details explanation saved me a lot of time.

  5. blake:

    Thank you very much, you saved me.

Leave a Reply

Comment Rules: Please use a real name or alias. Keywords are not allowed in the "name" field. If you use keywords, your comment will be deleted, or your name will be replaced with the alias from your email address. No foul language, please. Thank you for cooperating.

Instructions for code snippets: Wrap inline code in <code> tags; wrap blocks of code in <pre> and <code> tags. When you want your HTML to display on the page in a code snippet inside of <code> tags, make sure you use &lt; and &gt; instead of < and >, otherwise your code will be eaten by pink unicorns.