Hey there! đź‘‹
If you’ve built anything interactive on the web, you’ve definitely touched a Form. Login, Register, “Contact Us”—forms are everywhere.
In standard HTML, forms are pretty straightforward. But in React, things get a bit… interesting. You’ll often hear terms like “Controlled” and “Uncontrolled” components thrown around.
Confused? Don’t be. Today, I’m going to explain exactly what they are and which one you should use. Let’s simplify this!
1. Controlled Components (The “React Way”)
In a Controlled Component, React is in charge.
The value of the form input is stored in the component’s State (useState).
Every time you type a character, an onChange event fires, updates the state, and React re-renders the input with the new value. It’s a loop.
Here is how it looks:
import { useState } from "react";
const ControlledForm = () => {
const [name, setName] = useState("");
const handleSubmit = (e) => {
e.preventDefault();
alert(`Hello, ${name}!`);
};
return (
<form onSubmit={handleSubmit} className="p-4 border rounded">
<label className="block mb-2">Name:</label>
<input
type="text"
value={name} // 1. Value comes from State
onChange={(e) => setName(e.target.value)} // 2. Change updates State
className="border p-2 rounded w-full mb-4"
/>
<button type="submit" className="bg-blue-500 text-white px-4 py-2 rounded">
Submit
</button>
</form>
);
};
Why use this?
- Instant Validation: You can check the input while the user types (e.g., password strength).
- Conditional Disabling: Disable the submit button if the input is empty.
- Enforced Format: You can prevent the user from typing numbers in a text field, for example.
The downside? You write a bit more code. But for complex forms, it’s usually worth it.
2. Uncontrolled Components (The “HTML Way”)
In an Uncontrolled Component, the DOM is in charge.
React doesn’t constantly track the value. Instead, when you need the value (like when submitting), you “pull” it from the DOM using a Ref (useRef).
It feels a lot more like traditional HTML/JavaScript.
import { useRef } from "react";
const UncontrolledForm = () => {
const nameInputRef = useRef(null); // Create a Ref
const handleSubmit = (e) => {
e.preventDefault();
// Read the value directly from the DOM element
const name = nameInputRef.current.value;
alert(`Hello, ${name}!`);
};
return (
<form onSubmit={handleSubmit} className="p-4 border rounded">
<label className="block mb-2">Name:</label>
<input
type="text"
ref={nameInputRef} // Attach the Ref here
defaultValue="" // Use defaultValue, not value!
className="border p-2 rounded w-full mb-4"
/>
<button type="submit" className="bg-green-500 text-white px-4 py-2 rounded">
Submit
</button>
</form>
);
};
Why use this?
- Less Code: No need for
useStateoronChangehandlers for every single field. - Non-React Integration: Great if you’re mixing React with other libraries that manipulate the DOM directly.
- File Inputs:
<input type="file" />is almost always uncontrolled because React can’t set file values programmatically for security reasons.
So, Which One Should I Use?
As a general rule of thumb:
- Use Controlled Components for most things. It gives you more power and control over the data. If you need validation or dynamic UI updates, this is the way.
- Use Uncontrolled Components if you’re building a super simple form (like a quick newsletter signup), need to handle file uploads, or are migrating an old vanilla JS app to React.
Wrapping Up
There is no “wrong” answer, just the right tool for the job.
- Want total control? Go Controlled.
- Want quick and dirty (or working with files)? Go Uncontrolled.
Master both, and you’ll never fear a form again. Happy coding! 🚀