Form Handling

By Syncfusion®, Inc. · Last updated

Controlled components, text, textarea, select, checkbox, radio and special inputs, handling input, many inputs with one handler, form state, submission and resetting.

Introduction to Forms

A form is a part of a page where the user types or chooses information, and then sends it. Login boxes, search bars, sign-up pages and checkout pages are all forms.

A form is made of inputs (boxes, lists, tick boxes) and a submit button. In React, you keep what the user types in state, so your code always knows the current values.

Real-World Example

A bookshop checkout page has inputs for name, address and a delivery option. Each input is controlled: value={form.name} shows the state, and onChange updates it.

When the user clicks Place order, onSubmit calls e.preventDefault() and sends the form object to the server. The page does not reload.

In React, the values of a form are kept in state. Each input shows the state, and each change updates the state.

Controlled Components

A controlled component is an input whose value is managed by React state.

React controls what appears in the input by storing the value in state and updating it whenever the user types.

To make an input controlled, you need two props:

  • value — tells the input what value to display. It is usually connected to a state variable.
  • onChange — runs whenever the user changes the input. It updates the state with the new value.

Together, value and onChange keep the input and state in sync.

A controlled input: the user types, onChange saves the text in state, and value shows the state in the box

Input box

State name = "Asha"

onChange → setName

value=

Typing goes into state with onChange. The box shows the state with value. Round and round.

Type in the box. The greeting and the letter count change as you type, because they read the same name state.

Look at this line:

<input value={name} onChange={(e) => setName(e.target.value)} />
  • value={name} makes the box show the name state.
  • onChange runs on every key press. e.target.value is the text in the box now. setName saves it.

If you set value but forget onChange, the box is stuck. You cannot type in it, because nothing updates the state.

Form Input Elements

Each kind of input works in almost the same way: show the state, and update it on change. Only a few details are different.

Text Input

A text input is a one-line box for short text, such as a name. You saw it above.

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

Textarea

A textarea is a bigger box for long text, such as a review. In React, you set its text with value, the same as a text input.

<textarea
  value={review}
  onChange={(e) => setReview(e.target.value)}
  rows={4}
/>

Select Dropdown

A select shows a list of choices that opens when you click it. Put value and onChange on the <select>, not on the options.

<select
  value={genre}
  onChange={(e) => setGenre(e.target.value)}
>
  <option value="fiction">Fiction</option>
  <option value="biography">Biography</option>
</select>

Checkbox

A checkbox is a tick box. It is on or off, so its state is true or false.

A checkbox is different in two ways: use checked instead of value, and read e.target.checked instead of e.target.value.

<input
  type="checkbox"
  checked={wantsGift}
  onChange={(e) => setWantsGift(e.target.checked)}
/>

Radio Button

Radio buttons are a group of round buttons. The user can choose only one of them.

Give every radio in the group the same name. Each one is checked when the state matches its own value.

<input
  type="radio"
  name="format"
  value="paper"
  checked={format === "paper"}
  onChange={(e) => setFormat(e.target.value)}
/>
<input
  type="radio"
  name="format"
  value="ebook"
  checked={format === "ebook"}
  onChange={(e) => setFormat(e.target.value)}
/>

Quick summary of the five inputs:

InputShows the state withReads the new value fromState type
Text inputvaluee.target.valuetext
Textareavaluee.target.valuetext
Selectvalue on <select>e.target.valuetext
Checkboxcheckede.target.checkedtrue / false
Radio buttonchecked={state === value}e.target.valuetext

The lab below has all five kinds of input. Try each one and watch the summary change.

The grey box at the bottom shows all the state at once. It changes the moment you change any input.

Special Input Types

The <input> tag has many types. Each type gives the user a better box for one kind of data.

TypeWhat the user seesWhat you read
type="email"A box for an email address. Phones show the @ key.e.target.value (text)
type="password"A box that hides the letters with dotse.target.value (text)
type="number"A box for numbers, with up and down arrowse.target.value (text, so change it with Number(...))
type="date"A box with a calendar to pick a datee.target.value (text like "2026-11-03")
type="file"A button to choose a file from the computere.target.files (the chosen files)

Look at the number box:

onChange={(e) => setCopies(Number(e.target.value))}

A box always gives back text, even when type="number". Number(...) changes the text "3" into the number 3, so copies * 299 works.

A file input is the one input you do not control with value. You only read the chosen file in onChange. e.target.files?.[0]?.name means: the name of the first chosen file, if there is one.

Handling User Input

Every input change runs a handler: a function that saves the new value. You can write it inline, or as a named function.

// Inline: good for one short line
<input value={name} onChange={(e) => setName(e.target.value)} />

// Named function: good when you need more than one line
function handleNameChange(e: ChangeEvent<HTMLInputElement>) {
  setName(e.target.value.toUpperCase()); // save it in capital letters
}

<input value={name} onChange={handleNameChange} />

Because you save the value yourself, you can change it before you save it. The second example turns every letter into a capital letter as the user types.

Handling Multiple Inputs

A form with many inputs would need many useState lines and many handlers. A shorter way is to keep all values in one object, and use one handler for every input.

The trick is the name prop. Give each input a name that matches a key in the object. The handler reads e.target.name to know which key to update.

Look at this line in handleChange:

setOrder({ ...order, [name]: value });
  • ...order copies all the old values.
  • [name]: value changes only one key. If you type in the phone box, name is "phone", so only phone changes.

The square brackets mean "use the value of name as the key". Without them, the key would be the word name itself.

Form State Management

Form state management means planning what state your form needs, and keeping it tidy. A simple plan works for most forms:

  • One object for the values — all the fields the user fills in.
  • One true/false for sending — isSubmitting, so you can disable the button while it sends.
  • One value for the result — a success message, or an error message.
const [values, setValues] = useState({ name: "", email: "" });
const [isSubmitting, setIsSubmitting] = useState(false);
const [message, setMessage] = useState("");

Store only what you need. For example, "is the form empty?" does not need its own state. Work it out from values when you need it:

const isEmpty = values.name === "" && values.email === "";

Form Submission

When the user presses the submit button, the form fires a submit event. You handle it with onSubmit on the <form>.

Animation: pressing Submit fires onSubmit; preventDefault stops the reload, the values from state are sent to the server, and the page shows a message

Newsletter formname: "Asha"email: "asha@..."Subscribe user presses Submit 1. e.preventDefault()no page reloadpage reload 2. Send the valuessendToServer(state) 3. Show the result"Thanks, Asha!"

One press of Submit: stop the reload, use the values in state, then show the user what happened.

The steps are always the same:

  1. Call e.preventDefault(), so the page does not reload.
  2. Use the values from state. For example, send them to a server.
  3. Show the user what happened.

Fill in both boxes and press Join newsletter. The button says "Sending..." for one second. Then the thank-you message appears, and the console shows the data that was sent.

Pressing Enter inside a box also submits the form. You get this for free when you use onSubmit on a <form>.

Put onSubmit on the <form>, not onClick on the button. Then both the button and the Enter key submit the form.

Resetting Forms

To reset a form means to clear it, so it is ready to fill in again. In a controlled form, you reset it by setting the state back to the starting values.

Keep the starting values in one constant. Then you can use it both to start and to reset.

Add a book. The book goes into the list, and both boxes become empty, because setValues(emptyForm) put the state back to the start.

Look at the Clear button. It has type="button". A button inside a form submits the form by default. type="button" stops that, so Clear only clears.

Common mistakes

MistakeWhat you seeFix
value without onChangeYou cannot type in the boxAdd onChange that updates the state
Starting state as undefined instead of ""Console warning about switching from uncontrolled to controlledStart text state as ""
Using value on a checkboxThe tick does not changeUse checked and e.target.checked
Radio buttons with different namesMore than one can be chosenGive all radios in a group the same name
Using the number box value as a number"2" + 1 gives "21"Change it with Number(e.target.value)
Forgetting e.preventDefault() in onSubmitThe page reloads and the form is lostCall it first in the submit handler
A Clear button without type="button"Clicking Clear submits the formAdd type="button"
Forgetting [ ] around name in { [name]: value }A new key called "name" is addedWrite [name]: value
Changing the state object directly: values.name = "Asha"The box does not updateMake a copy: setValues({ ...values, name: "Asha" })

Check Yourself

Exercises

What to Remember

  • A controlled input shows state with value and updates it with onChange. Checkboxes use checked.
  • Keep many inputs in one state object, and use one handler with [e.target.name].
  • Submit with onSubmit and e.preventDefault(). Reset by setting the state back to the starting values.

Next: Form Validation