Loading lessons...
Controlled vs Uncontrolled Forms
Controlled vs Uncontrolled Forms
Form elements (<input>, <textarea>, <select>) maintain their own internal DOM state by default in traditional HTML. In React, there are two distinct ways to handle form input state: Controlled Components and Uncontrolled Components.
Controlled Components (Recommended)
In a Controlled Component, React component state is the single source of truth for the input's value. Input values are bound to state via value={state} and updated on user typing via onChange={handler}.
import { useState } from 'react';
function ControlledForm() {
const [email, setEmail] = useState('');
const handleSubmit = (e) => {
e.preventDefault();
console.log("Submitted email:", email);
};
return (
<form onSubmit={handleSubmit}>
<label>Email:</label>
<input
type="email"
value={email} // Value driven by React state
onChange={(e) => setEmail(e.target.value)} // State updated on keystroke
/>
<p>Current input length: {email.length} characters</p>
<button type="submit">Submit</button>
</form>
);
}
Benefits of Controlled Components
- Instant field validation on every keystroke.
- Dynamic input formatting (e.g. credit card spacing, phone number masks).
- Disabling submit buttons based on real-time field validation.
Uncontrolled Components
In an Uncontrolled Component, input data is handled directly by the browser's DOM. You query the DOM element's value when needed using a useRef.
import { useRef } from 'react';
function UncontrolledForm() {
const emailRef = useRef(null);
const handleSubmit = (e) => {
e.preventDefault();
// Read input value directly from DOM element ref!
console.log("Submitted email:", emailRef.current.value);
};
return (
<form onSubmit={handleSubmit}>
<label>Email:</label>
<input ref={emailRef} type="email" defaultValue="user@example.com" />
<button type="submit">Submit</button>
</form>
);
}
Summary & TL;DR
- Controlled Components: Input value is bound to React state (
value+onChange). React is single source of truth. - Uncontrolled Components: Input value is managed by the DOM; values are pulled using
useRef. - Controlled components are preferred for real-time validation and dynamic form logic.