React Forms · Controlled Components
React handles all common form elements — input, textarea, and select — in a consistent, predictable way using state and the onChange handler.
Each element represents user input differently, but the core idea is the same: the UI reflects the state, and the state updates as the user types or selects options.
value + onChange pair: React reads from state using value and writes back using onChange.textarea in React uses a value prop instead of inner text.select uses a single value on the <select> tag to track the selected option.name attribute for easier, dynamic state updates.Common pattern for any controlled form element in React:
useState (or part of a bigger form object).value to that state.onChange event.Generic pattern:
const [value, setValue] = useState("");<input value={value} onChange={(e) => setValue(e.target.value)} />This pattern is reused for input, textarea, and select — only the element type and UI change, not the state logic.
Text inputs are controlled by linking the value prop to a state variable and updating it via onChange.
// Controlled text input using React state
import React, { useState } from "react";
function InputExample() {
const [name, setName] = useState("");
const handleChange = (e) => setName(e.target.value);
return (
<div>
<h4>Input Example</h4>
<input
type="text"
className="form-control"
placeholder="Enter your name"
value={name}
onChange={handleChange}
/>
<p className="mt-2">Hello, {name || "Guest"}!</p>
</div>
);
}
export default InputExample;
In plain HTML, the content of a textarea goes between <textarea>...</textarea>. In React, textarea behaves just like an input: its content is controlled through the value prop.
// Controlled textarea that tracks message length
import React from "react";
function TextareaExample() {
const [message, setMessage] = React.useState("");
const handleChange = (e) => setMessage(e.target.value);
return (
<div>
<h4>Textarea Example</h4>
<textarea
className="form-control"
rows="3"
placeholder="Type your feedback..."
value={message}
onChange={handleChange}
/>
<p className="mt-2 text-muted">
{message.length}/200 characters typed
</p>
</div>
);
}
export default TextareaExample;
The select element uses a value prop to track the selected option. Changing it updates the associated state and triggers a re-render.
// Controlled select dropdown for choosing a country
import React from "react";
function SelectExample() {
const [country, setCountry] = React.useState("India");
const handleChange = (e) => setCountry(e.target.value);
return (
<div>
<h4>Select Dropdown Example</h4>
<select
className="form-select"
value={country}
onChange={handleChange}
>
<option value="India">India</option>
<option value="USA">USA</option>
<option value="Germany">Germany</option>
<option value="Japan">Japan</option>
</select>
<p className="mt-2">You selected: {country}</p>
</div>
);
}
export default SelectExample;
You can combine input, textarea, and select elements in a single controlled form by storing them in one state object.
// Single form state object for input, textarea, and select
import React from "react";
function FeedbackForm() {
const [form, setForm] = React.useState({
name: "",
feedback: "",
rating: "Good",
});
const handleChange = (e) => {
const { name, value } = e.target;
setForm((prevForm) => ({
...prevForm,
[name]: value,
}));
};
const handleSubmit = (e) => {
e.preventDefault(); // Stop page reload on submit
alert(JSON.stringify(form, null, 2));
};
return (
<form onSubmit={handleSubmit}>
<div className="mb-3">
<label>Name</label>
<input
type="text"
name="name"
className="form-control"
placeholder="Enter your name"
value={form.name}
onChange={handleChange}
/>
</div>
<div className="mb-3">
<label>Feedback</label>
<textarea
name="feedback"
className="form-control"
rows="3"
placeholder="Write your feedback..."
value={form.feedback}
onChange={handleChange}
/>
</div>
<div className="mb-3">
<label>Rating</label>
<select
name="rating"
className="form-select"
value={form.rating}
onChange={handleChange}
>
<option>Excellent</option>
<option>Good</option>
<option>Average</option>
<option>Poor</option>
</select>
</div>
<button className="btn btn-primary">Submit Feedback</button>
</form>
);
}
export default FeedbackForm;
onChange, updates name, and re-renders the greeting: Hello, <name>!.message. The paragraph below shows a live character count using message.length.country and the text You selected: ... reflects the new value.form object. On submit, the form is prevented from reloading the page using e.preventDefault(), and the final data is shown via alert(JSON.stringify(form, null, 2)).In all cases, state is the single source of truth for what appears in every form control.
handleChange function for multiple fields by relying on e.target.name and dynamic keys: [name].defaultValue when you only need an initial value and do not need the field to be fully controlled.e.preventDefault() in onSubmit handlers to prevent full page reloads for React forms.Goal: Master handling text, textarea, and select fields in React using state and unified change handlers for clean and controlled form management.