How to Handle Multiple Inputs with One React Handler

Update several React form fields with one handleChange that reads each input's name and updates only that key in a values object.

6 min read

A React form with multiple inputs does not need a handler per field. One handleChange can read the name attribute of the edited field and update just that key in a single values object. Checkboxes need their checked flag, while text inputs and selects keep using value.

Keeping one handler also means submit and validation read a single values object instead of many separate variables.

Keep all fields in one object

Store every field in one state object, then write a handler that copies the object and replaces the single edited key. Reading the key from the event is what makes one function work for every input.

App.jsxApp.jsx
import { useState } from "react";
 
export default function SignupForm() {
  const [values, setValues] = useState({ name: "", email: "", role: "", subscribe: false });
 
  function handleChange(e) {
    const { name, value, type, checked } = e.target;
    setValues({ ...values, [name]: type === "checkbox" ? checked : value });
  }
  // the return below continues this same component

The handler reads name, value, type, and checked from the event target. For a checkbox it stores checked, and for every other control it stores value, then it spreads the old object so the other fields stay untouched.

Give each field a matching name

Each control's name attribute must equal a key in the values object. When they line up, the same handler updates name, email, and role without any field-specific code. This return statement continues the SignupForm component above.

App.jsxApp.jsx
return (
  <form>
    <label htmlFor="name">Name</label>
    <input id="name" name="name" value={values.name} onChange={handleChange} />
    <label htmlFor="email">Email</label>
    <input id="email" name="email" type="email" value={values.email} onChange={handleChange} />
    <label htmlFor="role">Role</label>
    <select id="role" name="role" value={values.role} onChange={handleChange}>
      <option value="">Choose a role</option>
      <option value="admin">Admin</option>
      <option value="editor">Editor</option>
    </select>
  </form>
);

Type in either field and only that key changes in state. Selects read the same value property as text inputs, so they need no special case in the handler.

Always spread the old object before setting the new key. React detects a state change by comparing object references, so mutating the existing object and passing that same reference to setValues would make React skip the re-render, leaving the screen showing stale values even though the object changed underneath it.

Handle checkboxes with checked

A checkbox reports its state through the checked property, not value. Pass checked from state and let the handler branch on the input type.

App.jsxApp.jsx
<label>
  <input
    type="checkbox"
    name="subscribe"
    checked={values.subscribe}
    onChange={handleChange}
  />
  Send me updates
</label>

Ticking the box sets subscribe to true, and unticking sets it to false. The label wraps the control, so clicking the text toggles it too. Radio groups read checked the same way, but every option shares one name so the browser keeps only the selected value checked.

The same handler covers textareas and selects

A textarea reads and writes value exactly like a text input, and a select does too. The handler branches only on the checkbox type, so every other control flows through the value path unchanged.

App.jsxApp.jsx
<textarea name="bio" value={values.bio} onChange={handleChange} />

The textarea joins the shared handler by using the same name and value pair. Add bio to the initial values object and the field is complete.

Read the values in a summary

One values object also makes live previews trivial. Render the current values next to the form and they update as the user types.

App.jsxApp.jsx
<p>{values.name || "No name yet"}</p>
<p>{values.email || "No email yet"}</p>

The summary reads the same object the inputs write to, so no extra state or synchronization is needed. It stays in step with the fields automatically.

Why one object beats separate state

Storing each field in its own useState call works, but it scatters the form across many variables. Every new field needs its own setter, and submit has to reassemble the fields by hand. A single values object keeps the shape in one place and lets the handler target any key by name.

This is the same reason form libraries expose one values object. The object is easier to pass to validation and easier to reset, since clearing the form is one setValues call back to the initial shape.

Why one handler scales

One handler means adding a field is a one-line change: add a key to the initial state and a control with the matching name. The alternative is a separate handler and setter per field. Three fields become three functions and three setState calls, and each new field copies the same boilerplate again.

With one handler, the same growth adds one key and one control. The difference shows up most at six or eight fields, where the shared handler keeps the component flat.

The values object also gives submit and validation one place to read, and resetting the form is a single setValues call back to the initial shape. When you are ready, pass values into the validator from React form validation without a library, or review the controlled-input model in how to build forms in React. The tradeoff between state-driven and DOM-driven fields is explained in controlled vs uncontrolled forms in React.

Rune AI

Rune AI

Key Insights

  • Store all fields in one values object.
  • Read e.target.name to find the edited key.
  • Copy the object and replace one key immutably.
  • Use checked for checkboxes, value for text and selects.
  • The same handler feeds validation and submit.
RunePowered by Rune AI

Frequently Asked Questions

Why store all fields in one object instead of many useState calls?

One object keeps related form data together and lets a single handler update any field by name. It also gives validation and submit a single values object to read.

How does the handler know which field changed?

The event target carries the input's name attribute. The handler reads e.target.name and uses it as the object key to update.

Do checkboxes work with the same handler?

Yes. Read e.target.checked for checkboxes and radio groups instead of e.target.value, then decide between the two based on e.target.type.

Conclusion

One handleChange can drive every field in a form. Read the name from the event, copy the values object, and replace only the edited key, using checked for checkboxes.