How-To

How-To · State

How to Handle Form Input in React

Handle a text input in React by holding its value in useState, binding value={x}, updating state in onChange, and reading the value on submit — the controlled-component pattern.

XCODXHow-To · Updated

Overview

The standard way to handle a form field in React is the controlled component: React state holds the field's value, and the input simply displays it. You need this whenever you want to read what the user typed, validate it, or react to it as they type — which is almost always. The recommended approach is four small moves: hold the value in state, bind it to the input, update it on every change, and read it when the form is submitted.

Steps

1. Hold the value in useState

Every controlled input needs a piece of state to live in. Declare it with useState, giving it a sensible starting value — usually an empty string for a text field. This state variable is now the single source of truth for what the field contains; the input will show it and update it, but the value lives here in state, not in the DOM.

const [name, setName] = useState('');

2. Bind the input with value={x}

Connect the state to the input by setting its value attribute to the state variable. This is what makes the component controlled: the input can no longer hold its own value independently — it always displays exactly what is in state. On the first render the field shows the empty string you initialised, and from now on the field mirrors the state.

<input value={name} />

3. Update state in onChange

Because the input's value is pinned to state, typing alone cannot change it — you must update the state yourself. Add an onChange handler that reads the new text from event.target.value and passes it to the setter. Each keystroke fires onChange, the setter stores the new value and triggers a re-render, and the field shows the updated text. This tight loop — type, set state, re-render — is the heart of a controlled input.

<input
  value={name}
  onChange={(e) => setName(e.target.value)}
/>

4. Read the value on submit

When the form is submitted, the current value is already sitting in your state variable — no need to query the DOM. Add an onSubmit handler to the <form>, call event.preventDefault() to stop the browser from reloading the page, and use the state value directly. Because state has been kept in sync on every keystroke, it holds exactly what the user sees.

function handleSubmit(e) {
  e.preventDefault();
  console.log('Submitted:', name);
}

Runnable example

Here are all four steps together — a controlled text input whose value is held in state, updated on every change, and echoed live below the field. Type in it and watch the text appear as you go:

The echo under the input is reading straight from state, which is why it updates on every keystroke. Open it in the editor and try adding a second field. The same pattern extends to any number of fields: give each one its own piece of state, or hold them all in a single object and update by key.

Text fields are not the only controlled inputs. A checkbox and a <select> follow the same rule — bind them to state and update state on change — but each reads a different property of the event. A checkbox reflects event.target.checked, while a select reflects event.target.value. Here both drive a live summary line:

Common pitfalls

One more gotcha: remember event.preventDefault() in the submit handler. Without it the browser performs a full-page reload when the form submits, throwing away your component state before you can use it.

Frequently asked questions

What is a controlled component in React?
An input whose value is held in React state rather than in the DOM. You set the input's value from state and update that state in onChange, so state is always the single source of truth for the field.
How do I read a form value on submit in React?
You do not read the DOM — the value is already in your state variable. Add an onSubmit handler, call event.preventDefault(), and use the state value directly, since it was kept in sync on every keystroke.
Why is my React input not updating when I type?
You almost certainly set value from state but forgot the onChange handler. With value pinned to state and nothing updating that state, the field is effectively read-only. Add onChange={(e) => setName(e.target.value)}.
How do I handle multiple inputs in one form?
Give each field its own useState, or hold them all in one object of state and update by key with the updater form, for example setForm((prev) => ({ ...prev, email: e.target.value })).