Level 4 · Full-Stack Application Development · Course 4.1 React Fundamentals

Module 35: Forms and Validation in React

Goal: build forms in React that are pleasant to fill in, check input clearly, show helpful errors, and work for everyone, including keyboard and screen-reader users. You'll finish the enquiry dashboard project.

You'll need: your enquiries project from Module 34, and Module 13's form skills.

Lessons

  1. 1Form state15–25 minutes✓
  2. 2Validation rules15–25 minutes✓
  3. 3Error feedback15–25 minutes✓
  4. 4Accessible forms15–25 minutes✓
  5. 5Reusable form fields and form libraries15–25 minutes✓

🛠️Module practice: Course 4.1 project, a customer-enquiry dashboard

Finish the dashboard:

  1. A new-enquiry form with reusable fields, validation and accessible error messages.
  2. Enquiries listed with search, status filter, summary counts and status changes.
  3. Data remembered in localStorage.
  4. Tests for validation and any other pure logic.
  5. Works on a phone and with the keyboard; Lighthouse accessibility 90+. README and commit.

✅Module check

Explain in a few sentences, in your own words:

How do you build a React form that is easy and accessible to fill in, and validated properly?

Show a good answer

A good answer mentions: keep field values in one state object with one change handler, and handle submit with preventDefault; validate with a pure, tested function (or a schema library) that returns errors per field; show plain-language errors next to fields after they're visited or on submit, and move focus to the first error. Every field has a label, errors are linked with aria-describedby and aria-invalid, results are announced with role="status", and colour isn't the only signal. The server validates again.

📝Module quiz

10 questions · 10 marks each · 100 marks in all · pass mark 70% · retry as often as you like ·

1. What does [name]: value do in setForm(f => ({ ...f, [name]: value }))?

Why each option is right or wrong

  • “Creates an array called name that holds every value” (Incorrect): Square brackets here make a property name, not an array.
  • “Replaces the whole form with just the one field that changed” (Incorrect): ...f keeps the other fields; only the named one changes.
  • “Adds a new field literally called "name" each time” (Incorrect): The brackets use the variable's value, like "email", not the word name.
  • “Updates the field matching the input's name, keeping the others” is correct.

    ...f copies every existing field. [name]: value uses the input's name attribute as the property name, so name="email" updates email. One change handler can then serve every field in the form.

    • Square brackets: a computed property name, using the variable's value as the key.
    • Requirement: each input's name must match a field in the form state.

📖 Revise: Lesson 1: Form state

Question ID module-35-q1 · Report a mistake in this question
2. Why call event.preventDefault() in a React form's submit handler?

Why each option is right or wrong

  • “To stop other users seeing the form's contents” (Incorrect): It has nothing to do with privacy; it stops the reload.
  • “To validate every field before sending” (Incorrect): Validation is your own code. preventDefault only stops the browser's default action.
  • “To block the submit button from being pressed twice” (Incorrect): It doesn't disable the button; it stops the page reloading.
  • “To stop the browser's full-page reload” is correct.

    By default, submitting a form makes the browser send it and load a new page, wiping your React state. preventDefault() stops that, so your code can validate and send the data itself.

    • Where: first line of handleSubmit(e).
    • Symptom if forgotten: the page flashes and the form resets.

📖 Revise: Lesson 1: Form state

Question ID module-35-q2 · Report a mistake in this question
3. Why write validation as a separate pure function?

Why each option is right or wrong

  • “React won't let you write validation inside a component” (Incorrect): You can; it's just harder to test and reuse there.
  • “Pure functions run validation on the server automatically” (Incorrect): They don't move anywhere by themselves; you can reuse them on the server if you choose.
  • “It hides the validation rules from people using the form” (Incorrect): The goal is testable, reusable code, not hiding rules.
  • “It can be tested and reused, and keeps the component simple” is correct.

    A function like validate(form) that returns a list of errors needs no React or browser to run. You can test it with simple inputs, use the same rules on the server, and keep the component focused on showing the form.

    • Test: assert.deepEqual(validate({ email: "" }), { email: "Enter your email" }).
    • Shared rules: the same checks can run in the browser and on the server.

📖 Revise: Lesson 2: Validation rules

Question ID module-35-q3 · Report a mistake in this question
4. Your React form validates perfectly. Does the server still need to check?

Why each option is right or wrong

  • “No, browser validation can't be bypassed by anyone” (Incorrect): It can: requests can be sent without using your page.
  • “No, but only if the form uses TypeScript types” (Incorrect): Types are removed before running and don't protect the server.
  • “Only if the site has more than a thousand visitors” (Incorrect): One person with curl is enough to bypass the form.
  • “Yes, requests can be sent without your form” is correct.

    Anyone can send data straight to your server with tools like curl, skipping your form and its checks. Browser validation helps honest users; server validation protects your data from everyone.

    • Browser checks: fast feedback.
    • Server checks: the real protection.

📖 Revise: Lesson 2: Validation rules

Question ID module-35-q4 · Report a mistake in this question
5. Why not show "Invalid email" from the first letter typed?

Why each option is right or wrong

  • “Checking on each keystroke slows typing to a crawl” (Incorrect): Simple checks are fast; the problem is the confusing message.
  • “Email addresses can't be checked until they're sent” (Incorrect): You can check the format in the browser; the issue is timing.
  • “Showing errors early costs money on most hosting plans” (Incorrect): Validation runs in the browser; it doesn't cost hosting money.
  • “The person hasn't finished; early errors are confusing” is correct.

    Every email is "invalid" until it's complete. Showing an error after one letter feels like being told off for something you haven't done yet. A common approach is to validate when the field loses focus, or on submit, and then update live once an error is showing.

    • On blur: check when the person leaves the field.
    • After an error: update as they type, so it disappears as soon as it's fixed.

📖 Revise: Lesson 3: Error feedback

Question ID module-35-q5 · Report a mistake in this question
6. Why not just disable the submit button until the form is valid?

Why each option is right or wrong

  • “Disabled buttons can't be styled with CSS to look different from others” (Incorrect): They can be styled; the issue is that they don't explain anything.
  • “React doesn't support the disabled attribute” (Incorrect): React supports disabled; it's a usability choice.
  • “Disabling the button makes the browser submit the form by itself later” (Incorrect): Disabling doesn't send anything; it only blocks the button.
  • “A disabled button gives no reason, so people can't tell what to fix” is correct.

    People see a grey button and don't know why it won't work. Many screen readers skip disabled buttons too. Leaving it enabled and showing clear errors on submit tells people exactly what to change.

    • Better: let them press it, then show errors and focus the first one.
    • Disable briefly: while a submission is in progress, to prevent double sending.

📖 Revise: Lesson 3: Error feedback

Question ID module-35-q6 · Report a mistake in this question
7. What does aria-describedby="email-error" do?

Why each option is right or wrong

  • “Shows the error in a red tooltip when hovered” (Incorrect): It doesn't change what's seen; it links the message for assistive technology.
  • “Checks that the email address is in a valid format” (Incorrect): ARIA attributes describe; they don't validate.
  • “Hides the error message from sighted users of the page” (Incorrect): It doesn't hide anything; it connects the field and message.
  • “Links the field to its error message for screen readers” is correct.

    Screen readers read the element with id="email-error" along with the field, so a blind user hears "Email, invalid entry, enter an email like name@example.com" without hunting for the message.

    • Also add: aria-invalid="true" on fields with errors.
    • Ids must match: the message needs id="email-error".

📖 Revise: Lesson 4: Accessible forms

Question ID module-35-q7 · Report a mistake in this question
8. Is a red border enough to show an error?

Why each option is right or wrong

  • “Yes, red universally means error and everyone sees it” (Incorrect): Not everyone can tell red from other colours, and screen readers can't see borders.
  • “Yes, as long as the border is thick and bright enough to notice clearly” (Incorrect): Thickness doesn't help people who can't see the colour or use screen readers.
  • “No, but only because red is hard to see on mobile” (Incorrect): The main issue is colour blindness and screen readers, on any device.
  • “No, show error text too; some people can't see colour differences” is correct.

    Colour vision deficiency affects a significant share of people, and red borders alone are also missed by screen readers. A written message next to the field, ideally with an icon, works for everyone.

    • Rule: don't use colour as the only signal.
    • Message: say how to fix it, not just that it's wrong.

📖 Revise: Lesson 4: Accessible forms

Question ID module-35-q8 · Report a mistake in this question
9. What do libraries like React Hook Form do?

Why each option is right or wrong

  • “Design the visual style of every form on the site automatically” (Incorrect): They handle form logic; styling is still up to you.
  • “Send form data straight to a database without a server” (Incorrect): They don't replace a server or database.
  • “Replace the need for any server-side validation of the same data” (Incorrect): Server checks are still essential.
  • “Manage form state, validation and submission with less code” is correct.

    For bigger forms, these libraries handle field values, touched state, errors and submit logic, often with fewer re-renders. You still decide the rules and the messages.

    • Learn it by hand first: then you understand what the library does for you.
    • Often paired with: schema validators like Zod.

📖 Revise: Lesson 5: Reusable form fields and form libraries

Question ID module-35-q9 · Report a mistake in this question
10. Why build a TextField component instead of repeating markup?

Why each option is right or wrong

  • “React shows a warning when similar markup appears twice” (Incorrect): React doesn't warn about repeated markup.
  • “Components load faster than plain inputs in the browser” (Incorrect): Speed is about the same; the gain is consistency and fewer mistakes.
  • “Plain <input> elements can't be used in React forms” (Incorrect): Plain inputs work fine; a component just avoids repetition.
  • “Labels, errors and accessibility are written once and correct everywhere” is correct.

    Each field needs a label, an input, an error message and the right ARIA links. Writing them in one component means every form gets them right, and a fix in one place fixes every form.

    • Usage: <TextField label="Email" name="email" error={errors.email} />.
    • Consistency: every field looks and behaves the same.

📖 Revise: Lesson 5: Reusable form fields and form libraries

Question ID module-35-q10 · Report a mistake in this question

ProLearners Assist