Learn how to handle forms in React with controlled & uncontrolled inputs. Explore key concepts, implementation examples, and best practices.
Forms are one of the most essential aspects of user interaction in web applications. Whether it’s collecting feedback, user authentication, or other data from users, forms are a central feature. React, a popular JavaScript library, provides two methods for handling forms: controlled components and uncontrolled components. Both of these approaches come with their pros and cons.
Forms are an essential part of nearly every web application. They collect, manage, and send data to backend services. React simplifies the way forms are handled, making it easier to create interactive, responsive, and dynamic forms.
Forms are everywhere on the web. Whether it’s logging in to an account, submitting feedback, or making a purchase, forms act as a communication bridge between the user and the web application. How forms are handled can significantly impact the user experience, making form management a crucial part of front-end development.
In React, forms can be handled in two main ways: controlled components and uncontrolled components. The difference between the two lies in how the form’s data is managed and updated.
A controlled component is an input element whose value is controlled by the React state. In other words, React has full control over the form’s data. Every time a user types into a form field, React’s state gets updated, and this update propagates back to the component, making the input’s value always consistent with the React state.
In controlled components, the value of an input field is bound to the state of a component. This is done by setting the value
attribute of the input element to a state variable and updating the state when the user interacts with the input.
Example:
import React, { useState } from "react";
function ControlledForm() {
const [inputValue, setInputValue] = useState("");
const handleChange = (event) => {
setInputValue(event.target.value);
};
const handleSubmit = (event) => {
event.preventDefault();
console.log(inputValue);
};
return (
<form onSubmit={handleSubmit}>
<label>
Input:
<input type="text" value={inputValue} onChange={handleChange} />
</label>
<button type="submit">Submit</button>
</form>
);
}
To implement controlled components in React:
value
attribute of the form element to the state variable.onChange
handler to update the state when the input value changes.import React, { useState } from "react";
function RegistrationForm() {
const [formData, setFormData] = useState({
username: "",
email: "",
password: "",
});
const handleChange = (e) => {
const { name, value } = e.target;
setFormData((prevData) => ({
...prevData,
[name]: value,
}));
};
const handleSubmit = (e) => {
e.preventDefault();
console.log(formData);
};
return (
<form onSubmit={handleSubmit}>
<label>
Username:
<input
type="text"
name="username"
value={formData.username}
onChange={handleChange}
/>
</label>
<label>
Email:
<input
type="email"
name="email"
value={formData.email}
onChange={handleChange}
/>
</label>
<label>
Password:
<input
type="password"
name="password"
value={formData.password}
onChange={handleChange}
/>
</label>
<button type="submit">Submit</button>
</form>
);
}
An uncontrolled component is a form element where React does not directly manage the value of the input. Instead, the input maintains its own internal state. In this case, you don’t need to update the React state each time the input changes.
In uncontrolled components, the value of the input is stored in the DOM itself rather than in the React state. React accesses this value using refs.
Example:
import React, { useRef } from "react";
function UncontrolledForm() {
const inputRef = useRef();
const handleSubmit = (e) => {
e.preventDefault();
alert(`Input Value: ${inputRef.current.value}`);
};
return (
<form onSubmit={handleSubmit}>
<label>
Input:
<input type="text" ref={inputRef} />
</label>
<button type="submit">Submit</button>
</form>
);
}
To implement uncontrolled components in React:
ref
to get a reference to the form element.ref
when needed, usually on form submission.import React, { useRef } from "react";
function FeedbackForm() {
const nameRef = useRef();
const emailRef = useRef();
const messageRef = useRef();
const handleSubmit = (e) => {
e.preventDefault();
console.log({
name: nameRef.current.value,
email: emailRef.current.value,
message: messageRef.current.value,
});
};
return (
<form onSubmit={handleSubmit}>
<label>
Name:
<input type="text" ref={nameRef} />
</label>
<label>
Email:
<input type="email" ref={emailRef} />
</label>
<label>
Message:
<textarea ref={messageRef}></textarea>
</label>
<button type="submit">Submit</button>
</form>
);
}
Use state management libraries like React Hook Form or Formik to simplify form handling. These libraries help manage state, validation, and submissions more efficiently.
Form validation is essential for ensuring that the data submitted is accurate and complete. Libraries like Formik and React Hook Form provide built-in support for validation, making it easier to validate form inputs.
React form libraries help manage form state, validation, and submission more effectively. They also offer features like field-level validation, easy integration with UI frameworks, and better error handling.
Handling forms in React is an essential skill for any React developer. Whether you choose controlled components for complex forms or uncontrolled components for simpler forms, React provides flexibility in form management. By understanding the differences, advantages, and practical implementation of both approaches, you can create efficient and user-friendly forms in your applications.
For complex forms, use controlled components for better validation and state management. For simpler forms, consider uncontrolled components for better performance and reduced complexity. Regardless of the approach, best practices like using form libraries and managing state efficiently can significantly improve your React forms’ performance and user experience.