A controlled input’s value lives in React state. That is the usual pattern for forms you validate or submit with fetch.
function Login() {
const [email, setEmail] = useState('');
function onSubmit(e) {
e.preventDefault();
// send email to your API — this site does not collect this form
}
return (
<form onSubmit={onSubmit}>
<label>
Email
<input
type="email"
value={email}
onChange={(e) => setEmail(e.target.value)}
required
/>
</label>
<button type="submit">Continue</button>
</form>
);
}If you set value={email} and forget onChange, the field cannot be typed. Checkboxes use checked + e.target.checked.
Uncontrolled inputs use a ref and defaultValue — fine for an occasional file input or a throwaway demo. Prefer controlled for anything you need to validate live.