Creating Forms in React JS
Creating Forms in React JS is an essential skill for building interactive web applications. Forms allow users to enter, select, and submit information such as names, email addresses, passwords, contact details, feedback, and registration data. React provides form elements such as input, textarea, select, and button, along with Hooks such as useState to manage user input and form submission.
Course Link: JustAcademy React JS Training Course
Demo Link: Register for React JS Course Demo
1. Learning Objectives
After completing these notes, you will be able to:
- Understand the purpose of forms in React applications.
- Create forms using JSX and HTML form elements.
- Handle text inputs, email inputs, passwords, checkboxes, radio buttons, and dropdowns.
- Understand controlled and uncontrolled components.
- Manage form data using the
useState Hook.
- Handle form submission using the
onSubmit event.
- Prevent the browser's default form submission behavior.
- Validate user input and display appropriate error messages.
- Build a complete React registration form.
2. What Is a Form in React?
A form in React is a user interface element that collects information from users. React uses standard HTML form elements, but developers can connect those elements to React state and event handlers to manage their behavior.
Example: A registration form may collect a user's name, email address, password, and preferred course.
Basic HTML Form
<form>
<label for="name">Name:</label>
<input type="text" id="name" name="name">
<button type="submit">Submit</button>
</form>
Basic React Form
function MyForm() {
return (
<form>
<label htmlFor="name">Name:</label>
<input type="text" id="name" name="name" />
<button type="submit">Submit</button>
</form>
);
}
export default MyForm;
Important difference: In React JSX, use htmlFor instead of HTML's for attribute for labels. JSX also requires form elements to follow JSX syntax, including closing tags where appropriate.
3. Common Form Elements in React
| Element |
Purpose |
Example |
input type="text" |
Collects short text. |
Full name |
input type="email" |
Collects an email address. |
[email protected] |
input type="password" |
Collects a password. |
Account password |
input type="number" |
Collects numeric input. |
Age |
input type="checkbox" |
Allows independent selections. |
Accept terms |
input type="radio" |
Allows one selection from a group. |
Learning mode |
textarea |
Collects longer text. |
Feedback |
select |
Provides a dropdown list. |
Select a course |
button |
Submits or resets a form, or performs another action. |
Submit button |
4. Creating a Simple Form in React
The first step is to create a functional component containing a form and its input fields.
function ContactForm() {
return (
<form>
<h2>Contact Us</h2>
<label htmlFor="name">Full Name:</label>
<input type="text" id="name" name="name" />
<label htmlFor="email">Email:</label>
<input type="email" id="email" name="email" />
<label htmlFor="message">Message:</label>
<textarea id="message" name="message" rows="4" />
<button type="submit">Send Message</button>
</form>
);
}
export default ContactForm;
Explanation
form groups related input fields.
label describes the purpose of each input.
input collects short information.
textarea collects longer text.
button type="submit" submits the form.
name attributes identify fields when reading submitted form data.
This example creates the form interface. To process the submitted information in React, add an event handler such as onSubmit.
5. Handling Input Values with useState
The useState Hook allows a functional component to store and update data. When a user changes an input, an event handler can update state, and React renders the latest value.
Example: Managing a Name Input
import { useState } from "react";
function NameForm() {
const [name, setName] = useState("");
return (
<div>
<label htmlFor="name">Enter your name:</label>
<input
id="name"
type="text"
value={name}
onChange={(event) => setName(event.target.value)}
/>
<p>Your name is: {name}</p>
</div>
);
}
export default NameForm;
How It Works
useState("") creates a state variable called name with an empty initial value.
value={name} connects the input value to React state.
onChange runs when the user changes the input.
event.target.value reads the current input value.
setName() updates the state.
- The paragraph displays the updated value automatically.
6. What Is a Controlled Component?
A controlled component is a form element whose current value is managed by React state. The input receives its value through a prop such as value, and an event handler updates the state when the user edits it.
Example
import { useState } from "react";
function ControlledForm() {
const [email, setEmail] = useState("");
return (
<form>
<label htmlFor="email">Email:</label>
<input
id="email"
type="email"
value={email}
onChange={(event) => setEmail(event.target.value)}
/>
<p>Current email: {email}</p>
</form>
);
}
export default ControlledForm;
Advantages of Controlled Components
- React always has access to the current field value.
- Input values can be validated as users type.
- Fields can be cleared or updated programmatically.
- Conditional UI can depend on the user's input.
- Form submission can use the latest state values.
Important: A controlled text input should receive a string value throughout its lifetime. For example, initialize it with useState("") rather than allowing its value to switch between undefined and a string.
7. What Is an Uncontrolled Component?
An uncontrolled component stores its current value in the DOM rather than having React state control every change. React can provide an initial value through defaultValue, and the value can be read when needed using the DOM or the FormData API.
Example: Using FormData
function UncontrolledForm() {
function handleSubmit(event) {
event.preventDefault();
const formData = new FormData(event.currentTarget);
const name = formData.get("name");
const email = formData.get("email");
alert(`Name: ${name}\nEmail: ${email}`);
}
return (
<form onSubmit={handleSubmit}>
<label htmlFor="name">Name:</label>
<input id="name" name="name" defaultValue="" />
<label htmlFor="email">Email:</label>
<input id="email" name="email" type="email" />
<button type="submit">Submit</button>
</form>
);
}
export default UncontrolledForm;
Controlled vs. Uncontrolled Components
| Feature |
Controlled |
Uncontrolled |
| Value storage |
React state |
DOM element |
| Common prop |
value or checked |
defaultValue or defaultChecked |
| Change handling |
Usually requires onChange to update state. |
Can use the browser's built-in input behavior. |
| Validation while typing |
Easy to implement. |
Possible, but may require DOM access or other handlers. |
| Reading submitted values |
Read from React state. |
Read using FormData or a ref. |
| Typical use |
Dynamic forms and custom validation. |
Simple forms where direct state control is unnecessary. |
8. Handling Multiple Form Fields with One State Object
When a form contains several fields, you can store their values in one state object. Use the input's name attribute to determine which property to update.
import { useState } from "react";
function UserForm() {
const [formData, setFormData] = useState({
name: "",
email: "",
phone: ""
});
function handleChange(event) {
const { name, value } = event.target;
setFormData((previousData) => ({
...previousData,
[name]: value
}));
}
return (
<form>
<input
name="name"
placeholder="Full Name"
value={formData.name}
onChange={handleChange}
/>
<input
name="email"
type="email"
placeholder="Email"
value={formData.email}
onChange={handleChange}
/>
<input
name="phone"
type="tel"
placeholder="Phone"
value={formData.phone}
onChange={handleChange}
/>
<pre>{JSON.stringify(formData, null, 2)}</pre>
</form>
);
}
export default UserForm;
Explanation
formData stores the values of all three fields.
handleChange() reads the field name and its current value.
- The spread operator
... preserves the other field values.
[name]: value updates the property matching the input's name.
JSON.stringify() displays the current state as formatted JSON for learning purposes.
9. Handling Textarea in React
The textarea element is used when users need to enter longer text, such as comments, descriptions, or feedback. In React, a controlled textarea uses the value prop rather than placing its initial text between the opening and closing tags.
import { useState } from "react";
function FeedbackForm() {
const [feedback, setFeedback] = useState("");
return (
<form>
<label htmlFor="feedback">Your Feedback:</label>
<textarea
id="feedback"
value={feedback}
onChange={(event) => setFeedback(event.target.value)}
rows={4}
placeholder="Write your feedback here"
/>
<p>Characters entered: {feedback.length}</p>
</form>
);
}
export default FeedbackForm;
10. Creating Dropdowns with select
The select element allows users to choose an option from a dropdown list. A controlled dropdown uses the value prop and an onChange handler.
import { useState } from "react";
function CourseForm() {
const [course, setCourse] = useState("");
return (
<form>
<label htmlFor="course">Select a Course:</label>
<select
id="course"
value={course}
onChange={(event) => setCourse(event.target.value)}
>
<option value="">Choose a course</option>
<option value="react">React JS</option>
<option value="flutter">Flutter</option>
<option value="figma">Figma UI/UX</option>
</select>
<p>Selected course: {course || "None"}</p>
</form>
);
}
export default CourseForm;
When using a controlled dropdown, set the selected value on the parent select element. React does not use the HTML selected attribute on individual options for this pattern.
11. Handling Checkboxes
Checkboxes are useful for independent yes/no choices, preferences, or agreement to terms and conditions. A controlled checkbox uses the checked prop instead of value to represent its selected state.
import { useState } from "react";
function TermsForm() {
const [accepted, setAccepted] = useState(false);
return (
<form>
<label>
<input
type="checkbox"
checked={accepted}
onChange={(event) => setAccepted(event.target.checked)}
/>
I accept the terms and conditions.
</label>
<p>Accepted: {accepted ? "Yes" : "No"}</p>
</form>
);
}
export default TermsForm;
Use event.target.checked to read whether a checkbox is selected. Use event.target.value when you need the checkbox's associated data value.
12. Handling Radio Buttons
Radio buttons allow users to select one option from a group. Radio buttons that belong to the same group should share a name attribute.
import { useState } from "react";
function LearningModeForm() {
const [mode, setMode] = useState("online");
return (
<form>
<p>Choose a learning mode:</p>
<label>
<input
type="radio"
name="mode"
value="online"
checked={mode === "online"}
onChange={(event) => setMode(event.target.value)}
/>
Online
</label>
<label>
<input
type="radio"
name="mode"
value="classroom"
checked={mode === "classroom"}
onChange={(event) => setMode(event.target.value)}
/>
Classroom
</label>
<p>Selected mode: {mode}</p>
</form>
);
}
export default LearningModeForm;
13. Handling Form Submission with onSubmit
The onSubmit event handler runs when a form is submitted. By default, the browser may navigate or reload the page when a form is submitted. In a typical React client-side form, call event.preventDefault() when you want to handle submission without that default navigation.
import { useState } from "react";
function LoginForm() {
const [username, setUsername] = useState("");
function handleSubmit(event) {
event.preventDefault();
alert(`Welcome, ${username}!`);
}
return (
<form onSubmit={handleSubmit}>
<label htmlFor="username">Username:</label>
<input
id="username"
value={username}
onChange={(event) => setUsername(event.target.value)}
required
/>
<button type="submit">Login</button>
</form>
);
}
export default LoginForm;
Important Concepts
onSubmit handles form submission.
event.preventDefault() prevents the browser's default submission behavior.
required activates the browser's built-in required-field validation.
type="submit" identifies the button that submits the form.
14. Validating Form Data
Form validation checks whether the entered information meets the application's requirements before the data is accepted or sent to a server.
Common Validation Rules
- Required fields must not be empty.
- Email addresses must follow an acceptable format.
- Passwords must meet the application's password rules.
- Phone numbers must follow the expected format.
- Confirmation fields must match their corresponding values.
Example: Basic Validation
import { useState } from "react";
function ValidationForm() {
const [name, setName] = useState("");
const [error, setError] = useState("");
const [message, setMessage] = useState("");
function handleSubmit(event) {
event.preventDefault();
if (!name.trim()) {
setError("Name is required.");
setMessage("");
return;
}
setError("");
setMessage("Form submitted successfully!");
}
return (
<form onSubmit={handleSubmit} noValidate>
<label htmlFor="name">Name:</label>
<input
id="name"
value={name}
onChange={(event) => setName(event.target.value)}
/>
{error && <p role="alert">{error}</p>}
{message && <p role="status">{message}</p>}
<button type="submit">Submit</button>
</form>
);
}
export default ValidationForm;
Note: Client-side validation helps users correct mistakes, but important data must also be validated on the server.
15. Resetting a Form
A form reset returns form fields to their initial values. For a controlled form, update the React state as well as resetting the form's visible fields.
import { useState } from "react";
function ResetForm() {
const initialForm = { name: "", email: "" };
const [form, setForm] = useState(initialForm);
function handleChange(event) {
const { name, value } = event.target;
setForm((previous) => ({
...previous,
[name]: value
}));
}
function handleReset() {
setForm(initialForm);
}
return (
<form onReset={handleReset}>
<input
name="name"
placeholder="Name"
value={form.name}
onChange={handleChange}
/>
<input
name="email"
type="email"
placeholder="Email"
value={form.email}
onChange={handleChange}
/>
<button type="reset">Reset Form</button>
</form>
);
}
export default ResetForm;
For controlled inputs, resetting only the DOM does not reset the React state. Update the state to restore the intended values.
16. Styling Forms with CSS
CSS helps make forms organized, readable, and responsive.
.form-container {
max-width: 450px;
margin: 20px auto;
padding: 24px;
border: 1px solid #ddd;
border-radius: 8px;
}
.form-container label {
display: block;
margin: 12px 0 6px;
}
.form-container input,
.form-container select,
.form-container textarea {
box-sizing: border-box;
width: 100%;
padding: 10px;
border: 1px solid #999;
border-radius: 4px;
}
.form-container button {
margin-top: 16px;
padding: 10px 16px;
cursor: pointer;
}
Apply the class to the form:
<form className="form-container">
{/* Add form fields here */}
</form>
In JSX, use className rather than HTML's class attribute.
17. Complete Mini Project: Student Registration Form
This project combines controlled inputs, a dropdown, a checkbox, validation, submission handling, and a success message.
import { useState } from "react";
function StudentRegistrationForm() {
const initialForm = {
name: "",
email: "",
course: "",
termsAccepted: false
};
const [form, setForm] = useState(initialForm);
const [errors, setErrors] = useState({});
const [success, setSuccess] = useState("");
function handleChange(event) {
const { name, value, checked, type } = event.target;
setForm((previous) => ({
...previous,
[name]: type === "checkbox" ? checked : value
}));
setErrors((previous) => ({
...previous,
[name]: ""
}));
setSuccess("");
}
function handleSubmit(event) {
event.preventDefault();
const nextErrors = {};
if (!form.name.trim()) {
nextErrors.name = "Please enter your name.";
}
if (!form.email.trim()) {
nextErrors.email = "Please enter your email.";
} else if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(form.email)) {
nextErrors.email = "Please enter a valid email address.";
}
if (!form.course) {
nextErrors.course = "Please select a course.";
}
if (!form.termsAccepted) {
nextErrors.termsAccepted = "Please accept the terms.";
}
setErrors(nextErrors);
if (Object.keys(nextErrors).length === 0) {
setSuccess("Registration form submitted successfully!");
console.log("Student details:", form);
} else {
setSuccess("");
}
}
return (
<form onSubmit={handleSubmit} noValidate>
<h2>Student Registration</h2>
<label htmlFor="name">Full Name:</label>
<input
id="name"
name="name"
value={form.name}
onChange={handleChange}
aria-invalid={Boolean(errors.name)}
/>
{errors.name && <p role="alert">{errors.name}</p>}
<label htmlFor="email">Email Address:</label>
<input
id="email"
name="email"
type="email"
value={form.email}
onChange={handleChange}
aria-invalid={Boolean(errors.email)}
/>
{errors.email && <p role="alert">{errors.email}</p>}
<label htmlFor="course">Choose Course:</label>
<select
id="course"
name="course"
value={form.course}
onChange={handleChange}
aria-invalid={Boolean(errors.course)}
>
<option value="">Select a course</option>
<option value="react">React JS</option>
<option value="flutter">Flutter</option>
<option value="figma">Figma UI/UX</option>
</select>
{errors.course && <p role="alert">{errors.course}</p>}
<label>
<input
type="checkbox"
name="termsAccepted"
checked={form.termsAccepted}
onChange={handleChange}
/>
I accept the terms and conditions.
</label>
{errors.termsAccepted && (
<p role="alert">{errors.termsAccepted}</p>
)}
{success && <p role="status">{success}</p>}
<button type="submit">Register</button>
<button type="button" onClick={() => {
setForm(initialForm);
setErrors({});
setSuccess("");
}}>
Clear Form
</button>
</form>
);
}
export default StudentRegistrationForm;
Project Workflow
- The user enters their name and email address.
- The user selects a course from the dropdown.
- The user accepts the terms and conditions.
- The user clicks the Register button.
- React validates the fields and stores any errors.
- If errors exist, the form displays the corresponding messages.
- If all checks pass, the form displays a success message.
Important: This project demonstrates front-end form handling only. It does not store student details in a database or create a real registration. Connect a backend API to save the data in a real application.
18. Common Mistakes When Creating Forms in React
| Mistake |
Explanation |
Correct Practice |
Using class |
JSX uses a different attribute name for CSS classes. |
Use className. |
Using for on labels |
React JSX uses a different label attribute. |
Use htmlFor. |
Forgetting onChange |
A controlled input may not update as expected. |
Update state synchronously in onChange. |
| Mixing controlled and uncontrolled inputs |
The input's management approach may change during its lifetime. |
Use value or defaultValue consistently. |
Using value for a checkbox |
It does not control whether the checkbox is selected. |
Use checked. |
Forgetting preventDefault() |
The browser may reload or navigate away during submission. |
Prevent the default when handling submission in client-side code. |
| Missing input names |
FormData uses field names to identify submitted values. |
Add a meaningful name to fields whose data must be collected. |
| Using a default submit button unintentionally |
A button inside a form defaults to submitting. |
Set type="button" for non-submit actions. |
19. Best Practices for Creating React Forms
- Use meaningful names for form fields and state properties.
- Provide a visible label for every input.
- Choose controlled or uncontrolled inputs according to the form's needs.
- Use
useState for form values that affect the UI.
- Keep event handlers clear and reusable.
- Use appropriate input types such as
email, password, and tel.
- Validate user input and display clear error messages.
- Disable duplicate submission when an asynchronous request is in progress.
- Use accessible labels and error descriptions.
- Validate submitted data on the server as well as on the client.
- Never store passwords or sensitive information in unnecessary logs.
- Consider a form library for large or complex forms with extensive validation requirements.
20. Interview Questions and Answers
Q1. What is a form in React?
A form is a user interface that collects information through input fields, dropdowns, checkboxes, radio buttons, and other controls.
Q2. What is a controlled component?
A controlled component is a form element whose current value is managed by React state and updated through event handlers.
Q3. What is an uncontrolled component?
An uncontrolled component keeps its current value in the DOM. Its value can be read through a ref or by using FormData during submission.
Q4. Why is useState used in React forms?
useState stores input values and other form-related information, such as errors, loading states, and success messages.
Q5. What is the purpose of onChange?
The onChange handler responds when the user changes a form field. For controlled inputs, it normally updates the corresponding React state.
Q6. What does event.preventDefault() do?
It prevents the browser's default action for an event. In a typical client-side form submission handler, it prevents the browser from performing the default form navigation or reload.
Q7. What is the difference between value and defaultValue?
value specifies the current value of a controlled input, while defaultValue specifies its initial value for an uncontrolled input.
Q8. How do you handle a checkbox in React?
Use checked to control its selected state and event.target.checked to read the new boolean value.
Q9. How can you get multiple field values during submission?
You can store values in React state or use new FormData(event.currentTarget) inside the form's submission handler.
Q10. How do you validate a form in React?
Check the field values against the required rules, store any validation errors in state, display the messages, and submit the data only when the checks pass. The server should also validate the submitted data.
21. Practice Exercises
- Create a login form with username and password fields.
- Create a contact form with name, email, phone, and message fields.
- Build a dropdown that lets users select a course.
- Create a checkbox that records whether the user accepts terms and conditions.
- Build a radio-button group for selecting online or classroom learning.
- Display the current input values below a controlled form.
- Add required-field and email-format validation.
- Implement a reset button that clears all controlled fields.
- Build a registration form with validation errors and success feedback.
- Submit form data to a test API and display loading, success, and failure states.
22. Quick Revision Checklist
- Understand JSX form elements.
- Know the difference between controlled and uncontrolled components.
- Use
useState to manage field values.
- Handle text inputs, textareas, dropdowns, checkboxes, and radio buttons.
- Use
onSubmit to handle form submission.
- Use
event.preventDefault() when overriding default client-side submission behavior.
- Validate fields before processing submitted data.
- Display accessible error and success messages.
- Reset controlled form state correctly.
- Understand why server-side validation is necessary.
23. Official Learning Resources
24. Conclusion
Creating forms in React involves building input fields, managing values, handling user interactions, validating data, and processing submissions. Controlled components are useful when the application needs direct control over input values, while uncontrolled components can simplify forms that only need values at submission time. By practicing form elements, state management, validation, and submission handling, you can build reliable and user-friendly forms for real-world React applications.
Explore More: JustAcademy React JS Training Course | Register for React JS Course Demo