Lesson 7 — Typed controlled forms and validation¶
Objective¶
Build a study-session form with explicit draft state, validation, and accessible feedback.
Prerequisites¶
Lesson 6 — React Router and lazy routes. You should be comfortable with controlled inputs and event handlers.
Mental Model¶
Controlled inputs make React state the source of truth. Validation is a domain decision; browser constraints can improve UX but do not replace trusted-boundary validation.
Concept¶
A controlled form keeps every input value in state. Draft state stays as strings or raw input values until the user submits. At submission, the code validates the values and converts them into a domain object. Errors are announced and associated with fields so assistive technology can find them.
Example¶
function SessionForm({ onSubmit }: { onSubmit: (s: Session) => void }) {
const [topic, setTopic] = useState('');
const [minutes, setMinutes] = useState('');
const handleSubmit = (e: FormEvent) => {
e.preventDefault();
const parsed = Number(minutes);
if (!Number.isFinite(parsed) || parsed < 1 || parsed > 240) return;
onSubmit({ topic, minutes: parsed });
};
return (
<form onSubmit={handleSubmit}>
<label htmlFor="topic">Topic</label>
<input id="topic" value={topic} onChange={(e) => setTopic(e.target.value)} />
{/* ... */}
</form>
);
}
Real-World Usage¶
Checkout flows, settings panels, scheduling tools, and any form where user input must be parsed, validated, and reported clearly.
Common Mistakes¶
- Converting input strings to numbers before the user finishes typing.
- Relying only on HTML5 validation for security or business rules.
- Announcing errors visually but not programmatically.
Mini Lab¶
Task¶
Capture topic, integer minutes, and notes. Require 1–240 minutes and meaningful notes. Dispatch a valid session, reset successful drafts, and preserve invalid input for correction.
Constraints¶
- Test submission by accessible roles.
- Check labels, focus behavior, status announcements, whitespace, decimals, and boundary values.
Expected Result¶
Invalid submissions are blocked with clear, per-field feedback. Valid submissions dispatch a Session object and reset the form without losing the user's place.
Hints¶
Keep draft strings as strings until validation so partially entered numbers remain representable. Convert into a domain object only after checks pass.
Knowledge Check¶
- Controlled versus uncontrolled forms?
- When should validation run?
- How do you prevent duplicate submissions for async saves?
Challenge¶
A stakeholder wants real-time validation after every keystroke. What are the risks, and how would you balance feedback timing with accessibility?
Summary¶
Controlled forms own input state. Validate at the domain boundary and communicate errors accessibly.