How to fix Warning: Received both `onChange` and `onInput` events for input in React

ReactBEGINNERLOWUpdated Dec 9, 2025· 128 views

React warns when an input element has both onChange and onInput event handlers because they serve the same purpose and can cause duplicate event handling. In React, onChange handles text input changes, making onInput redundant. Removing the duplicate handler simplifies code and eliminates the warning.

Quick fix

Fixes Warning: Received both `onChange` and `onInput` events for input

// ❌ WRONG - both handlers attached
function InputForm() {
  const [value, setValue] = useState('');
  
  const handleChange = (e) => {
    setValue(e.target.value);
  };
  
  const handleInput = (e) => {
    setValue(e.target.value);
  };
  
  return (
    <input
      value={value}
      onChange={handleChange}
      onInput={handleInput}  // Duplicate!
    />
  );
}
  1. Identify which handler you actually need
  2. Remove the onInput handler and keep only onChange
  3. Merge event handler logic if both were doing different things
  4. Check for third-party component wrappers
react — error
// ❌ WRONG - both handlers attached
function InputForm() {
const [value, setValue] = useState('');
const handleChange = (e) => {
setValue(e.target.value);
};
const handleInput = (e) => {
setValue(e.target.value);
};
return (
<input
value={value}
onChange={handleChange}
onInput={handleInput} // Duplicate!
/>
);
}
Warning: Received both `onChange` and `onInput` events for input

What this error means

React fires both onChange and onInput events when an input's value changes, but these handlers are often used redundantly. In React's virtual DOM, both onChange and onInput are automatically normalized to the same internal event type. When you attach both handlers to the same input element, React processes both, potentially executing the same logic twice or causing confusing behavior. This warning exists to help developers avoid unnecessary complexity and performance issues from duplicate event handlers. In vanilla JavaScript, onChange fires when focus is lost, while onInput fires immediately on each keystroke. However, React abstracts this difference and treats onChange as the standard way to handle input value changes across all input types. By attaching both, you're likely doing redundant work and may end up with bugs where logic accidentally runs twice.

Typical symptoms

  • Console shows warning "Warning: Received both `onChange` and `onInput` events for input"
  • Input event handlers fire twice for a single keystroke
  • State updates appear to happen multiple times when you type
  • Form validation or side effects triggered twice per character entered
  • Difficult to debug because handlers are executing more than expected
  • Performance degradation when typing in large forms with many inputs

Common causes

  1. Attaching both onChange and onInput handlers to the same input element
  2. Migrating code from vanilla JavaScript where onInput and onChange have different behaviors
  3. Copy-pasting input elements from different sources and forgetting to consolidate handlers
  4. Misunderstanding React's event normalization and thinking onChange only fires on blur
  5. Using third-party UI libraries that attach onInput while you attach onChange
  6. Accidentally defining both handlers in component class instances or functional components

How to fix "Warning: Received both `onChange` and `onInput` events for input"

1Identify which handler you actually need

First, determine whether you need onInput or onChange. In React, onChange is the standard and recommended approach for input value changes. If you're listening for real-time input changes (every keystroke), onChange is correct. Remove onInput entirely.

jsx
// ❌ WRONG - both handlers attached
function InputForm() {
  const [value, setValue] = useState('');
  
  const handleChange = (e) => {
    setValue(e.target.value);
  };
  
  const handleInput = (e) => {
    setValue(e.target.value);
  };
  
  return (
    <input
      value={value}
      onChange={handleChange}
      onInput={handleInput}  // Duplicate!
    />
  );
}
2Remove the onInput handler and keep only onChange

Delete the onInput handler from your input element and keep only onChange. In React, onChange handles all input value changes in real-time, so onInput is redundant.

jsx
// ✅ CORRECT - only onChange
function InputForm() {
  const [value, setValue] = useState('');
  
  const handleChange = (e) => {
    setValue(e.target.value);
  };
  
  return (
    <input
      value={value}
      onChange={handleChange}
    />
  );
}
3Merge event handler logic if both were doing different things

If your onChange and onInput handlers were executing different logic, combine that logic into a single handler:

jsx
// ❌ WRONG - split logic
function SearchInput() {
  const [query, setQuery] = useState('');
  const [results, setResults] = useState([]);
  
  const handleChange = (e) => {
    const val = e.target.value;
    setQuery(val);
  };
  
  const handleInput = (e) => {
    const val = e.target.value;
    // Perform search
    setResults(performSearch(val));
  };
  
  return (
    <input
      value={query}
      onChange={handleChange}
      onInput={handleInput}  // Duplicate logic
    />
  );
}

// ✅ CORRECT - combined logic
function SearchInput() {
  const [query, setQuery] = useState('');
  const [results, setResults] = useState([]);
  
  const handleChange = (e) => {
    const val = e.target.value;
    setQuery(val);
    setResults(performSearch(val));
  };
  
  return (
    <input
      value={query}
      onChange={handleChange}
    />
  );
}
4Check for third-party component wrappers

If you're using a custom input component or third-party UI library, verify that the wrapper doesn't already attach onInput. You may only need to provide your own onChange:

jsx
// Custom input wrapper that handles events
function CustomInput({ onChange, onInput, ...props }) {
  // ❌ If component internally attaches onInput, don't pass onInput from parent
  return (
    <input
      onChange={onChange}
      {...props}
    />
  );
}

// Usage - only provide onChange
function MyForm() {
  const [value, setValue] = useState('');
  
  return (
    <CustomInput
      value={value}
      onChange={(e) => setValue(e.target.value)}
      // Don't provide onInput
    />
  );
}

Check the third-party library documentation to understand what events it handles internally.

5Verify the fix by testing input behavior

After removing onInput, test that your input still responds correctly to user typing:

1. Type in the input field and verify characters appear
2. Open the browser console (F12) and confirm no warning appears
3. Check that state updates happen once per keystroke (not twice)
4. If you have event handlers triggering side effects (like validation or search), confirm they run the expected number of times
5. Use React Developer Tools to inspect the component and verify handlers are being called correctly

You can temporarily add logging to confirm handlers fire once:

jsx
const handleChange = (e) => {
  console.log('onChange fired', e.target.value); // Should log once per keystroke
  setValue(e.target.value);
};
6Audit your codebase for other duplicate handlers

Use your editor's find-in-files feature to search for similar patterns:

bash
# Search for other instances of both onChange and onInput
grep -r "onChange.*onInput" src/
grep -r "onInput.*onChange" src/

Or use your IDE's regex search to find input elements with both handlers:
- Pattern: onChange[^>]*onInput|onInput[^>]*onChange
- In Visual Studio Code, use Ctrl+Shift+F (Find in Files) with regex enabled

Fix any other occurrences following the same pattern.

Advanced notes

React's event system includes normalization between browser standards and cross-browser compatibility. Historically, browsers had inconsistent behavior: onChange fired only on blur in older versions, while onInput fired on every keystroke. React standardized this by making onChange behave like onInput (firing in real-time). If you need to support very old browsers (pre-2010), consult your browser compatibility requirements, but modern React applications should never need onInput.

For controlled components (where React state drives the input value), onChange is the only correct handler. For uncontrolled components (where the DOM maintains state), you typically wouldn't use either handler unless you need to react to changes. Some developers confuse ref-based uncontrolled inputs with needing onInput; in fact, uncontrolled inputs rarely need event handlers at all.

If you're implementing a complex input component that wraps a native input, ensure your wrapper exposes only the onChange handler to consumers and manage any internal event handling within the wrapper without exposing onInput to the outside world.

Frequently asked questions

What does "Warning: Received both `onChange` and `onInput` events for input" mean?
React fires both onChange and onInput events when an input's value changes, but these handlers are often used redundantly. In React's virtual DOM, both onChange and onInput are automatically normalized to the same internal event type. When you attach both handlers to the same input element, React processes both, potentially executing the same logic twice or causing confusing behavior.
How do I fix "Warning: Received both `onChange` and `onInput` events for input"?
React warns when an input element has both onChange and onInput event handlers because they serve the same purpose and can cause duplicate event handling. In React, onChange handles text input changes, making onInput redundant. Removing the duplicate handler simplifies code and eliminates the warning.
What causes "Warning: Received both `onChange` and `onInput` events for input"?
Attaching both onChange and onInput handlers to the same input element Migrating code from vanilla JavaScript where onInput and onChange have different behaviors Copy-pasting input elements from different sources and forgetting to consolidate handlers
Is the "Warning: Received both `onChange` and `onInput` events for input" error serious?
It is a low-severity error — more of a blocker than a risk. The steps above resolve it.

Official resources & further reading