React onChange Explained for Inputs, Selects, and Checkboxes

React onChange fires on every edit and keeps controlled fields in sync. Learn the right prop and event property for inputs, selects, and checkboxes.

5 min read

In React, onChange is the event prop that fires as the user edits an input, picks an option, or toggles a checkbox. It is the idiomatic way to keep a controlled field in sync with state, and it fires on every edit rather than waiting for blur. The prop name differs from the native DOM event, but in React onChange is the one you almost always want.

Control a text input

A controlled input gets its value from React state and reports edits back through onChange. The field shows exactly what state holds, so React stays the single source of truth, and you can read or transform the value at any time without asking the DOM.

App.jsxApp.jsx
import { useState } from "react";
function EmailField() {
  const [email, setEmail] = useState("");
  return (
    <label>
      Email
      <input type="email" value={email} onChange={(e) => setEmail(e.target.value)} />
    </label>
  );
}

Typing updates state on every keystroke, and the input echoes the value back. The event target is the input element, so e.target.value holds the latest text. Because the state updates synchronously in the handler, the field never falls out of step with what React renders.

Checkboxes use checked

Checkboxes do not use value. Pass the checked prop and read e.target.checked in the handler. The checked prop holds a boolean, so the field can only be on or off.

App.jsxApp.jsx
import { useState } from "react";
function ConsentCheckbox() {
  const [agreed, setAgreed] = useState(false);
  return (
    <label>
      <input type="checkbox" checked={agreed} onChange={(e) => setAgreed(e.target.checked)} />
      I agree to the terms
    </label>
  );
}

Clicking the box flips the state, and the box reflects the new value. Reading e.target.checked instead of e.target.value is the rule that catches most checkbox bugs, because value on a checkbox is a fixed string rather than the on or off state.

Selects use value like inputs

A select element works the same way as a text input. Put onChange on the select and read e.target.value, which matches the selected option's value attribute. The options stay ordinary HTML; only the select itself carries the controlled prop.

App.jsxApp.jsx
import { useState } from "react";
function PlanPicker() {
  const [plan, setPlan] = useState("free");
  return (
    <select value={plan} onChange={(e) => setPlan(e.target.value)}>
      <option value="free">Free</option>
      <option value="pro">Pro</option>
    </select>
  );
}

Choosing Pro sets plan to pro, and the select reopens on that option. Textareas follow the text input pattern: pass value and onChange, and the text content is controlled by the value prop rather than the children.

How the three controls differ

The controlled prop and the event property to read change from one control to the next.

ControlControlled propRead from the event
Text input and textareavaluee.target.value
Checkboxcheckede.target.checked
Selectvaluee.target.value

onChange fires on every edit

React fires onChange immediately on each change, which matches the browser's input event more closely than the native change event that waits for blur. The onInput prop also exists and behaves similarly, but onChange is the idiomatic choice in React and what most examples and libraries use. A change handler can therefore run before the user leaves the field, so validation can respond as the user types.

Rules that trip people up

A few rules cover most debugging time when a controlled field misbehaves.

  • Passing value without onChange freezes the field, because React keeps forcing the old value on every render.
  • A checkbox needs checked, not value.
  • value must stay a string. Start empty state as an empty string, not null or undefined.
  • An uncontrolled field uses defaultValue or defaultChecked instead, and reads values only when needed.
  • Updating state asynchronously can make the caret jump, so set the value synchronously in the handler.

The uncontrolled approach is the topic of the FormData guide, which is useful when you do not need to track every keystroke.

What to learn next

Handlers often need to know which field changed, and a handler shared by several fields can read the name from the event target to tell them apart. Typing event handlers adds the types once TypeScript enters the project, and the event handling overview covers the click side of the same pattern.

Rune AI

Rune AI

Key Insights

  • onChange fires on every edit, not only on blur.
  • Text inputs and selects use the value prop.
  • Checkboxes use checked and read e.target.checked.
  • A controlled field needs onChange or it becomes read-only.
  • Keep value a string and start empty state as an empty string.
RunePowered by Rune AI

Frequently Asked Questions

Does React onChange fire on blur or on every keystroke?

On every edit. React normalizes onChange to behave like the browser input event, so it fires immediately as the user types or changes a field.

Why does my input not update when I type?

You likely passed value without an onChange handler. A controlled field must update its state synchronously in onChange, or the field is read-only.

What should I read for a checkbox?

Read e.target.checked instead of e.target.value. Checkboxes use the checked prop, and checked holds the true or false state.

Conclusion

onChange keeps a controlled field in sync with React state. Pass value for text inputs and selects, checked for checkboxes, and read the matching property from the event target.