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 thenamestate.onChangeruns on every key press.e.target.valueis the text in the box now.setNamesaves 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:
| Input | Shows the state with | Reads the new value from | State type |
|---|---|---|---|
| Text input | value | e.target.value | text |
| Textarea | value | e.target.value | text |
| Select | value on <select> | e.target.value | text |
| Checkbox | checked | e.target.checked | true / false |
| Radio button | checked={state === value} | e.target.value | text |
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.
| Type | What the user sees | What 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 dots | e.target.value (text) |
type="number" | A box for numbers, with up and down arrows | e.target.value (text, so change it with Number(...)) |
type="date" | A box with a calendar to pick a date | e.target.value (text like "2026-11-03") |
type="file" | A button to choose a file from the computer | e.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 });
...ordercopies all the old values.[name]: valuechanges only one key. If you type in the phone box,nameis"phone", so onlyphonechanges.
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:
- Call
e.preventDefault(), so the page does not reload. - Use the values from state. For example, send them to a server.
- 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
| Mistake | What you see | Fix |
|---|---|---|
value without onChange | You cannot type in the box | Add onChange that updates the state |
Starting state as undefined instead of "" | Console warning about switching from uncontrolled to controlled | Start text state as "" |
Using value on a checkbox | The tick does not change | Use checked and e.target.checked |
Radio buttons with different names | More than one can be chosen | Give 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 onSubmit | The page reloads and the form is lost | Call it first in the submit handler |
A Clear button without type="button" | Clicking Clear submits the form | Add type="button" |
Forgetting [ ] around name in { [name]: value } | A new key called "name" is added | Write [name]: value |
Changing the state object directly: values.name = "Asha" | The box does not update | Make a copy: setValues({ ...values, name: "Asha" }) |
Check Yourself
Exercises
What to Remember
- A controlled input shows state with
valueand updates it withonChange. Checkboxes usechecked. - Keep many inputs in one state object, and use one handler with
[e.target.name]. - Submit with
onSubmitande.preventDefault(). Reset by setting the state back to the starting values.
Next: Form Validation