Before this lesson

Understand elements, attributes and links. Use sample data for the exercises.

What you will be able to do

Explain the different roles of label, id and name, distinguish validity from trust, and inspect the data that a form submits.

Understand the mechanism

An id identifies a document element and lets label reference it. A name supplies the key used in submitted form data; an id alone does not create that key. A form represents an input task rather than a random collection of controls. Group related radio buttons with fieldset and legend so their shared question is available without relying on visual position.

required and type=email provide early feedback, but client-side validation is not a server trust boundary: it can be bypassed. GET generally puts successful control data in the URL query; POST generally places it in the request body. POST itself is not encryption. A real server still needs business-rule validation and appropriate transport protection.

Runnable example

<form>
  <label for="email">Email</label>
  <input id="email" name="email" type="email" required>
  <button type="submit">Check</button>
</form>

Trace and verify

Submit an empty value and inspect required-field feedback. Try an invalid email format, then [email protected]. With the default GET behavior, examine the resulting query string. Remove the name attribute and repeat: that control no longer contributes its value. There is no receiving backend here, so navigation is not proof of successful registration.

Common mistakes and boundaries

A placeholder does not replace a persistent label. A button inside a form may submit by default; use type="button" for auxiliary actions. Disabled controls are normally omitted from submission, while readonly controls can still contribute values. Explain errors in text rather than relying only on a red outline.

Practice challenge

Add a required nickname limited to 30 characters and an auxiliary button that does not submit. Explain why maxlength alone cannot guarantee valid server input.

Reference solution and reasoning

Give the nickname an id, name and matching label. Mark the auxiliary button type="button". maxlength is a UI constraint; the server must still validate type, length and permitted content, returning field-specific feedback rather than describing every rejection as a network failure.

<label for="nickname">Nickname</label>
<input id="nickname" name="nickname" required maxlength="30">
<button type="button">Show instructions</button>

Lab: visible inputs are not necessarily submitted

A form submits an entry list, not every visible value. A missing name, a disabled control and an unchecked checkbox have different effects. This experiment constructs FormData without making a network request, letting you inspect the contract before adding a server.

Run this separate experiment in a modern browser Console; it is not a replacement for the main example above.

const form = new DOMParser().parseFromString(`<form><input name="course" value="html" readonly>
<input name="level" value="beginner" disabled>
<input value="visible-but-unnamed">
<input type="checkbox" name="news" value="yes">
<input type="checkbox" name="topic" value="html" checked>
<input type="checkbox" name="topic" value="css" checked></form>`, 'text/html').forms[0];
const data = new FormData(form);
console.log(JSON.stringify([...data]));
console.log(JSON.stringify(data.getAll('topic')));
console.assert(!data.has('level') && !data.has('news'));
console.assert(data.getAll('topic').length === 2);

Expected observations

Entries are course=html, topic=html and topic=css, in that order. getAll returns ["html","css"]. The readonly field is included; the disabled field is not.

Why this happens and where it stops applying

Object.fromEntries collapses repeated names into one property, which can silently lose checkbox selections. Use getAll for array-valued fields and validate each item. readonly describes normal UI editing, not trust: a caller can construct another request. Constructing FormData does not itself perform full constraint validation. A server must independently validate required fields, types, ranges and authorization.

Extension challenge

Add an initially unchecked agree field. How would you distinguish an absent field from an explicit value of no?

Reasoned solution

Use value=yes and required on the checkbox and requestSubmit for the normal validation path. The receiver checks that the field exists and equals yes. Absence is not the string no. If an API expects a Boolean, map the accepted value explicitly; Boolean("false") is true.

Further reading