Forms & User Input
Advanced · 20 min read · ▶ live playground · ✦ checkpoint
Forms are how pages collect real user input: names, emails, choices, search terms, settings, messages. In JavaScript, the main form move is simple: listen for the submit event, stop the browser's page-changing default when you want an in-page interaction, then read the named fields.
That last phrase matters. Good form code starts with the form, not with one random button click, because a form can be submitted by a button, by Enter in a text field, or by browser assistive behavior.
Submit is the form event
A submit event fires on the <form> when the user submits the form. For an in-page UI, your handler usually starts with event.preventDefault() so the browser does not navigate away or reload before your JavaScript result stays on screen.
Then use new FormData(form) to read the fields by their name attributes. FormData is the clean path because it understands forms as forms: inputs, selects, textareas, checkboxes, radio groups, and submit-ready field names.
Try the form. Change the fields, submit it, and notice that the result updates without the preview leaving the lesson.
Every field in that form has a name. Without a name, FormData skips the field because the browser would not know what key to submit. The input's id helps labels and selectors; the name is the field key.
Direct .value reads still have a place. If you are updating a live character counter for one textarea, messageInput.value.length is clearer than building a whole FormData object. But for submit handling, prefer FormData(form) because the code stays attached to the form shape instead of a pile of individual selectors.
data.get(name) returns one value for that field name. If several fields share a name, as checkbox groups often do, use data.getAll(name) to get all submitted values.
Names turn fields into data
Forms can collect different input types without changing the submit pattern. You still listen to submit, prevent the page-changing default for an in-page result, and read named values.
This playground uses direct .value for a live message count while using FormData for the actual submit.
The input event above is ordinary form feedback: it fires when the value changes, so the counter can respond as the user types. The submit handler still owns the real save action. Lesson 15.4 will go deeper on keyboard and pointer events; here the point is form flow.
Checkboxes are worth one small note. An unchecked checkbox is not included in FormData at all. That is why the code checks whether data.get("followup") === "yes" instead of expecting "no".
Let HTML validate first
HTML has built-in constraint validation. You add constraints in markup, and the browser can test whether the form satisfies them:
requiredmeans the field must have a value.minlength="3"means the text must be at least three characters.type="email"asks for an email-shaped value.
JavaScript can ask the form about those rules. form.checkValidity() returns a boolean. form.reportValidity() asks the browser to show its validation UI and returns the same kind of boolean. Browser message wording varies, so treat the exact popup text as browser-owned.
This demo uses novalidate so JavaScript can control the submit flow and show a custom status line every time. The constraints still work: checkValidity() and reportValidity() read the same rules.
There are two layers working together. HTML owns the basic rules in attributes, which keeps the markup honest even before JavaScript runs. JavaScript owns the custom feedback pattern: add classes, write a helpful status line, and decide when to call reportValidity().
setCustomValidity(message) lets your code attach a custom validation problem to a field. An empty string clears that custom problem. The demo clears the custom message while the user types, then sets it again on submit if the field is still wrong.
The validation rule is not "replace HTML with JavaScript." It is: let HTML describe the constraints, then use JavaScript to make the in-page experience clearer.
Next, the events get more specific. Keyboard events, pointer events, and custom events let you respond to lower-level interactions and let your own components announce what happened.
Checkpoint
Answer all three to mark this lesson complete