Phase 3 · Browser DevelopmentModule 19~40 min read

Forms & Validation

Collect, validate, and serialize user input while keeping forms accessible and secure.

What you'll learn

A form is an accessible data-and-interaction contract. JavaScript enhances it with domain validation and async feedback while preserving native semantics.

By the end of this lesson, you'll be able to:

  • Read forms with FormData
  • Combine native and custom validation
  • Report errors accessibly

Core mental model

Use this decision table as a compact reference. Focus on what each tool means and when it earns its place in production code.

ConceptWhat it meansDecision rule
Constraint validationBrowser checks required, type, range, and pattern rulesExpress simple constraints in HTML first
FormDataSuccessful controls serialized as key-value pairsUse instead of manual field scraping
Server validationTrusted boundary validates every requestNever treat client validation as security

Professional workflow

Build the behavior in small, observable steps. Each step should leave something you can inspect or test.

  1. Describe the form submission boundary: inputs, outputs, state, timing, and expected failures.
  2. Implement the smallest correct path with names that expose intent.
  3. Add edge cases and failure handling before introducing abstractions.
  4. Verify behavior with realistic data and one deliberately adversarial example.
  5. Refactor only after the observable behavior is protected.

Make behavior observable

Before optimizing or abstracting, make inputs, outputs, state changes, timing, and failure paths visible. JavaScript becomes much easier to reason about when hidden work is exposed.

Guided code lab

Validate a password confirmation

Custom validity integrates a domain rule with the browser's normal reporting.

password-form.js
const form = document.querySelector("#signup");
const password = form.elements.password;
const confirmation = form.elements.confirmation;
confirmation.addEventListener("input", () => {
  confirmation.setCustomValidity(
    confirmation.value === password.value ? "" : "Passwords must match",
  );
});

Serialize a valid submission

The submitter checks the whole form before creating a data object.

submit.js
form.addEventListener("submit", event => {
  event.preventDefault();
  if (!form.reportValidity()) return;
  const data = Object.fromEntries(new FormData(form));
  console.log(data.email);
});

Production practice

Contract

Keep the form submission API explicit: accepted state, emitted events, DOM ownership, and cleanup.

Verification

Test with keyboard input, missing elements, repeated initialization, and teardown—not only a mouse happy path.

Operations

Measure user-visible latency and remove listeners, observers, object URLs, or media tracks when the feature ends.

Common failure mode

Showing only a red border gives screen-reader and color-blind users no useful explanation or recovery path.

Independent workshop

Build an accessible registration form with synchronous and simulated server errors.

Your finished workshop must include:

  • Native HTML constraints
  • One cross-field custom rule
  • Focus and text feedback for invalid submission

Definition of done

Demonstrate the happy path and at least two edge cases, keep responsibilities separated, and add a short note explaining one design choice.

Recap & quick check

Key takeaways

  • Start with semantic form controls
  • FormData follows browser submission rules
  • Client checks improve UX
  • The server remains the authority

Quick check

1. What does FormData collect?

2. Where must security validation occur?

3. What clears a custom validity error?

Keep the workshop. Later modules deliberately build on these decisions, so each exercise can become part of your final portfolio architecture.