In React, what's the difference between onChange and onInput?

JavascriptReactjsDom Events

Javascript Problem Overview


I've tried searching around for an answer to this, but most of them are outside the context of React, where onChange triggers upon blur.

In performing various tests, I can't seem to tell how these two events are different (when applied to a textarea). Can anyone shed some light on this?

Javascript Solutions


Solution 1 - Javascript

It seems there is no real difference

React, for some reason, attaches listeners for Component.onChange to the DOM element.oninput event. See the note in the docs on forms:

React docs - Forms

There are more people that are surprised by this behavior. For more details, refer to this issue on the React issue tracker:

Document how React's onChange relates to onInput #3964

Quote from the comments on that issue:

> I don't understand why React chose to make onChange behave like onInput does. As fas as I can tell, we have no way of getting the old onChange behaviour back. Docs claim it's a "misnomer" but not it isn't really, it does fire when there's a change, just not until the input also loses focus. > >For validation, sometimes we don't want to show validation errors until they're done typing. Or maybe we just don't want a re-render on every keystroke. Now the only way to do that is with onBlur but now we also need to check that the value has changed manually. > >It's not that big of a deal, but it seems to me like React threw away a useful event and deviated from standard behaviour when there was already an event that does this.

I agree 100% with the comment... But I guess changing it now would bring more problems than it solves since so much code had already been written that relies on this behavior.

React is not part of the official Web API collection

Even though React is built on top of JS, and has seen a huge adoption rate, as a technology React exists to hide a whole lot of functionality under its own (fairly small) API. Once area where this is obvious is in the event system, where there's a lot going on under the surface that's actually radically different from the standard DOM event system. Not just in terms of which events do what, but also in terms of when data is allowed to persist at what stage of the event handling. You can read more about that here:

React Event System

Solution 2 - Javascript

There is no difference

React does not have the behaviour of default 'onChange' event. The 'onChange' which we see in react has the behaviour of default 'onInput' event. So to answer your question there is no difference in both of them in react. I have raised an issue on GitHub regarding the same and this is what they have to say about it:

> I think that at the time this decision was made (~4 years ago?), onInput didn’t work consistently between browsers, and was confusing to people coming to the web from other platforms, as they would expect the “change” event to fire on every change. In case of React it is a bigger issue because if you fail to handle change soon enough, the controlled inputs never update, leading people to think React is broken. So the team went with calling it onChange. > > In retrospect it might have been a better idea to polyfill onInput and keep its name rather than change the behavior of another event. But that ship has sailed a long time ago. We might revisit this decision in the future, but I would just encourage you to treat it as a quirk of React DOM (which you’ll get used to pretty quickly).

https://github.com/facebook/react/issues/9567

Also this article will provide more insight. As a workaround for default 'onChange' being missing, the article suggests listening to the 'onBlur' event.

https://www.peterbe.com/plog/onchange-in-reactjs

Solution 3 - Javascript

For anyone who stumbled over this issue looking for a way to listen for the actual, DOM-based change event, this is how I did it (written in TypeScript):

import { Component, createElement, InputHTMLAttributes } from 'react';

export interface CustomInputProps {
    onChange?: (event: Event) => void;
    onInput?: (event: Event) => void;
}

/**
 * This component restores the 'onChange' and 'onInput' behavior of JavaScript.
 *
 * See:
 * - https://reactjs.org/docs/dom-elements.html#onchange
 * - https://github.com/facebook/react/issues/3964
 * - https://github.com/facebook/react/issues/9657
 * - https://github.com/facebook/react/issues/14857
 */
export class CustomInput extends Component<Omit<InputHTMLAttributes<HTMLInputElement>, 'onChange' | 'onInput' | 'ref'> & CustomInputProps> {
    private readonly registerCallbacks  = (element: HTMLInputElement | null) => {
        if (element) {
            element.onchange = this.props.onChange ? this.props.onChange : null;
            element.oninput = this.props.onInput ? this.props.onInput : null;
        }
    };

    public render() {
        return <input ref={this.registerCallbacks} {...this.props} onChange={undefined} onInput={undefined} />;
    }
}

Please let me know if you see ways to improve this approach or encounter problems with it. Unlike blur, the change event is also triggered when the user presses enter and is only triggered if the value actually changed.

I'm still gaining experience with this CustomInput component. For example, checkboxes behave strangely. I either have to invert event.target.checked in the onChange handler while passing the value to the checkbox with checked or get rid of this inversion when passing the value to the checkbox with defaultChecked but this then breaks that several checkboxes representing the same state in different places on the page keep in sync. (In both cases, I didn't pass an onInput handler to the CustomInput for checkboxes.)

Solution 4 - Javascript

One difference seems to be that onChange is not fired when selecting and replacing a character with the same character, while onInput is.

See this sandbox: https://codesandbox.io/s/react-onchange-vs-oninput-coggf?file=/src/App.js

  • Type "A" in the field, then select all and type "B". This will trigger 4 events, 2 onChange and 2 onInput.
  • Now select all and type "B" again, this till trigger a new onInput event, but no onChange.

Solution 5 - Javascript

As you can see in various comments here, React treats onChange and onInput the same and so, rather than debate the merits of this decision. Here's the solution.

Use onBlur when you don't want to process the user's edits until they're done. :)

Solution 6 - Javascript

Recently I got a bug where onChange would not allow copy and paste in the input field on IE11. Whereas the onInput event would allow that behavior. I could not find any documentation that would describe this in the docs, but that does show there is a difference between the two (expected or not).

Solution 7 - Javascript

The difference is that the oninput event occurs immediately after the value of an element has changed, while onchange occurs when the element loses focus, after the content has been changed.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionffxsamView Question on Stackoverflow
Solution 1 - JavascriptStijn de WittView Answer on Stackoverflow
Solution 2 - JavascriptNikhil GoyalView Answer on Stackoverflow
Solution 3 - JavascriptKaspar EtterView Answer on Stackoverflow
Solution 4 - JavascriptPer EnströmView Answer on Stackoverflow
Solution 5 - Javascriptchad steeleView Answer on Stackoverflow
Solution 6 - JavascriptAlan SouzaView Answer on Stackoverflow
Solution 7 - JavascriptSuzan View Answer on Stackoverflow