Forms
Learn how to build a basic HTML form in JSX, handle submission with onSubmit and preventDefault, and preview controlled vs uncontrolled inputs.
Introduction
Forms are how applications collect information from users — signing up, logging in, searching, checking out. Since a React app is still just HTML under the hood, you build forms using the same familiar elements: form, input, label, and button, all written directly in JSX.
In this lesson you will build a basic form, learn how to handle its submission with onSubmit, stop the browser's default page reload with event.preventDefault(), and collect a couple of field values when the form is submitted. You will also get a preview of the two different philosophies React offers for managing form inputs — controlled and uncontrolled components — which the next two lessons cover in depth.
- How to structure a basic HTML form with inputs, labels, and a submit button in JSX.
- How to handle form submission with the onSubmit prop.
- Why event.preventDefault() is essential to stop a full page reload.
- How to read a couple of field values at the moment of submission.
- The difference between controlled and uncontrolled form philosophies, at a glance.
Building a Basic Form
A React form looks almost identical to a plain HTML form — you use a <form> element containing <label> and <input> elements, plus a submit <button>. The main JSX-specific detail is using the htmlFor attribute instead of HTML's for, since for is a reserved word in JavaScript.
function ContactForm() {
return (
<form>
<label htmlFor="name">Name</label>
<input type="text" id="name" name="name" />
<label htmlFor="email">Email</label>
<input type="email" id="email" name="email" />
<button type="submit">Send</button>
</form>
);
}Name [___________]
Email [___________]
[ Send ]htmlFor, not for
JSX uses htmlFor because "for" is a reserved keyword in JavaScript.
Familiar Elements
form, input, label, and button work exactly like their plain HTML counterparts.
type="submit"
Marks the button that triggers the form's onSubmit event when clicked.
Handling onSubmit
By default, submitting an HTML form reloads the entire page and sends the data to a server URL — behavior inherited from decades-old web standards. In a React app, you almost always want to intercept this and handle the submission with JavaScript instead. You do that by attaching an onSubmit handler to the <form> element and calling event.preventDefault() as the very first line.
function BasicSubmit() {
function handleSubmit(event) {
event.preventDefault(); // stop the default page reload
console.log("Form submitted!");
}
return (
<form onSubmit={handleSubmit}>
<input type="text" placeholder="Type something" />
<button type="submit">Submit</button>
</form>
);
}Form submitted!If you forget event.preventDefault(), clicking submit reloads the whole page, which wipes out every bit of your component state and defeats the purpose of building a single-page React app.
Collecting Field Values on Submit
A common pattern for a simple form is to read each field's current value directly from the event only at the moment of submission, using event.target — the form element itself — and its named elements.
function SignupForm() {
function handleSubmit(event) {
event.preventDefault();
const name = event.target.name.value;
const email = event.target.email.value;
console.log("Name:", name);
console.log("Email:", email);
}
return (
<form onSubmit={handleSubmit}>
<label htmlFor="name">Name</label>
<input type="text" id="name" name="name" />
<label htmlFor="email">Email</label>
<input type="email" id="email" name="email" />
<button type="submit">Sign Up</button>
</form>
);
}Name: Priya
Email: priya@mail.comHere, event.target.name and event.target.email work because each input's name attribute matches a property on the form element, giving quick access to raw values without wiring up state for every keystroke.
Two Philosophies: Controlled vs Uncontrolled
The example above reads values only when the form is submitted, letting the DOM manage each input's value the whole time you are typing. This is the foundation of what React calls an uncontrolled component. The alternative is to have React state drive the input's value on every keystroke, known as a controlled component. Both are valid, and React fully supports each style.
Controlled Components
React state is the single source of truth for the input's value, updated via value + onChange.
Uncontrolled Components
The DOM itself keeps track of the input's value; React reads it only when needed, often via a ref.
Neither approach is "wrong" — controlled components give you real-time access to input values (great for validation and dynamic UI), while uncontrolled components can be simpler for straightforward forms. The next two lessons dig into each in depth.
Common Mistakes
- Forgetting event.preventDefault(), causing a full page reload on submit.
- Using for instead of htmlFor on a <label>, which JSX does not recognize.
- Not giving inputs a name attribute, then being unable to read them off event.target.
- Mixing controlled and uncontrolled patterns on the same input without realizing it, which triggers React warnings.
Best Practices
- Always call event.preventDefault() as the first line of an onSubmit handler.
- Give every input a clear name attribute so it is easy to reference later.
- Pair every input with a <label> using htmlFor for accessibility.
- Use type="submit" on the button that should trigger the form's onSubmit.
- Decide upfront whether a form should be controlled or uncontrolled, and stay consistent within it.
Frequently Asked Questions
Why does the button need type="submit"?
It tells the browser this button should trigger the form's submit event when clicked, which is what fires the onSubmit handler on the <form>.
Can I attach onSubmit to the button instead of the form?
You could add an onClick to the button, but attaching onSubmit to the <form> is the standard approach — it also correctly handles submission triggered by pressing Enter inside a text field.
What does event.target refer to inside a submit handler?
It refers to the <form> element itself, and its named inputs become accessible as properties, like event.target.email.
Is it fine to read values only on submit instead of tracking every keystroke?
Yes, this uncontrolled style is completely valid for simple forms where you do not need to react to every change, such as live validation or a character counter.
Which approach will the rest of the course focus on?
Both are covered — the next lesson dives into controlled components in depth, followed by a dedicated lesson on the uncontrolled approach.
Key Takeaways
- A React form uses the same form, input, label, and button elements as plain HTML.
- JSX uses htmlFor instead of HTML's for attribute on labels.
- Attach onSubmit to the form and call event.preventDefault() to stop the default page reload.
- You can read field values at submission time via event.target.<fieldName>.value.
- React supports two form philosophies — controlled components (state-driven) and uncontrolled components (DOM-driven) — covered next.
Summary
Building a form in React starts with familiar HTML elements, plus one essential habit: handling onSubmit and calling event.preventDefault() so the page never reloads. From there, you can read field values directly at submission time — a lightweight, uncontrolled-style approach.
In this lesson, you learned how to structure a basic form, handle its submission, and collect field values, along with a preview of the controlled vs uncontrolled philosophies. Next, you will explore controlled components in depth, where React state fully drives every input.
- You can build a basic form with inputs, labels, and a submit button.
- You can handle onSubmit and prevent the default page reload.
- You can read field values from event.target on submission.
- You understand the difference between controlled and uncontrolled forms, at a glance.