Skip to content
wannacode

Forms

In short: An HTML form collects data in labelled fields with a name attribute and sends them with a button, while required, type, min, max and pattern check them in the browser.

Problem

An order with no data

The shop gets orders with no name and no phone. The buyers swear they filled in everything. Here is the checkout form. Fill it in and press "Place order".

HTML, CSS, JS
index.html

The sandbox sends nothing over the network. Instead the console says what would have been sent: "The form was sent: (no fields)". Everything you typed stayed on the page. There is a second sign too: a click on the word "Name" does not put the cursor in the field. On screen the text and the field sit next to each other, but nothing in the tree links them.

The idea

The form, the name and the label

A form (<form>) collects fields and sends them together. action says where to (/order), and method says how (post).

<form action="/order" method="post">
<label for="phone">Phone</label>
<input id="phone" name="phone" type="tel">
<button type="submit">Place order</button>
</form>
  • name is what gets sent. On submit the browser makes a pair name=value for every field with a name: phone=0888123456. A field with no name is not sent, however full it is. That is why the order was empty.
  • <label> is the label of the field. It is linked with for, which points to the id of the field. The field can also sit inside the label: <label>Phone <input name="phone"></label>. Then for is not needed.

The label gives the field a name in the accessibility tree. A screen reader says "Phone, edit text", not just "edit text". A click on the label focuses the field, and a checkbox with a label can be ticked by its text. The checks in the tasks find the field by its label, the way a person does.

id and name are often the same, but they do different jobs. The id is for the label and for CSS, and the name is the key in the request.

The idea

The kinds of fields

<input> is one field, and type says what it is:

  • text (the default), email, tel: text. On a phone email and tel open a keyboard with @ or with digits.
  • number: a number, with arrows. min="1", max="10" and step="1" give the limits and the step.
  • checkbox: a yes-or-no tick. It is sent only when ticked: gift=yes from value="yes". Without a value it sends gift=on.
  • radio: one choice out of several. Radio buttons form a group by a shared name: name="delivery" on both, and value says which one is chosen. Only the chosen one is sent.

Other fields:

  • <select> with <option>: a drop-down. It sends the value of the chosen option, or its text when there is no value.
  • <textarea>: text on several lines, like a note for the courier.
  • <fieldset> with <legend>: a group of fields with a title. The delivery radio buttons are in a fieldset, and the legend "Delivery" is the name of the group. Without it a screen reader says "To an office", but not what the office is for.

The button. <button type="submit"> sends the form. <button type="button"> does nothing by itself, and its action is in JavaScript. Inside a form a <button> with no type is submit. So always write the type.

See it

The whole checkout

The checkout form with every kind of field. Fill it in, change the city and the delivery and press "Place order". Tick "Wrap as a gift" and press again.

HTML, CSS, JS
index.html

Look at the line in the console. The pairs are in the order of the fields in the code. The city is plovdiv: the value is sent, not the text "Plovdiv". From the delivery only the chosen button is there. The checkbox is missing until it is ticked. The empty note is sent as note=: an empty field with a name is still a field.

Try it

Fix the checkout

Fix the form from the start so that the order arrives whole. The texts "Name", "Phone" and "Address" become the labels of their fields, and the fields get the names name, phone and address.

HTML, CSS, JS
index.html

Try it

Find the bug

The buyer types a discount code and presses "Apply the code". The order is sent before they have typed their email. Which line is to blame?

Pick the line with the bug.

Try it

Fill in

Which attribute of the label points to the id of the field?

<label ="email">Email</label>
<input id="email" name="email" type="email">

The idea

The checks of the browser

An order with the email iva or with a quantity of 0 should not be sent. The browser can check a lot by itself, without a line of JavaScript. The rules are attributes of the field:

  • required: the field cannot be empty. For a checkbox: it must be ticked. For a radio group: something must be chosen.
  • type="email": the text must look like an email (name@domain). An empty field passes if there is no required.
  • min and max: the limits of a number. step is the step: with step="1", 2.5 does not pass.
  • minlength and maxlength: how many characters at least and at most.
  • pattern: a pattern for the whole text, like a regular expression. pattern="0[0-9]{9}" is a 0 and nine more digits.

When "Place order" is pressed, the browser checks every field. If one does not pass, the form is not sent and the submit event does not happen at all. The browser focuses the first invalid field and shows a message next to it in the language of the browser. The buyer fixes it, presses again, and the browser checks from the start.

novalidate on the <form> turns these checks off. It is used when the page checks and shows the errors with its own code. The lesson about forms in components is about that.

See it

See what happens on "Place order"

The code is a short checkout form. Watch the order: first the check, then the event, then the collecting.

<form action="/order" method="post">
<label>Name <input name="name" required></label>
<label>Email <input name="email" type="email" required></label>
<label>Phone <input name="phone" pattern="0[0-9]{9}"></label>
<label>Quantity <input name="qty" type="number" min="1" max="10"></label>
<label><input name="gift" type="checkbox"> Gift</label>
<button>Place order</button>
</form>
Step by step, in words
  1. The buyer presses "Place order". The <button> has no type, so inside a form it is a submit button. The browser does not send anything yet.
  2. First it checks every field in the order of the code against its rules. "iva" is not an email, and "12345" does not match the pattern.
  3. There are invalid fields, so the submit event does not happen. The browser focuses the first invalid field and shows a message only for it.
  4. The buyer fixes the email and the phone and presses again.
  5. The same check from the top. This time every field passes.
  6. Only now does the submit event happen. If the code does not stop it, the browser sends the form to action with method.
  7. It collects a name=value pair from every field with a name. The unchecked checkbox is not sent at all.
  8. With method="post" the pairs go in the body of the request, joined with &. The key is the name attribute, not the text of the label.

The browser checks all the fields, but shows a message only for the first invalid one. That is why a buyer sometimes fixes one field and right away sees a message for the next. And gift is not sent at all: for the server an unticked checkbox and a missing field are the same thing.

Try it

Add the checks

The quick order for the bread lets everything through. Add checks: the quantity is from 1 to 10, the email is required and must be an email, the phone is required and is a 0 and nine more digits. The check types 12, an empty email, "iva", an empty and a wrong phone, and expects the browser to stop on the right field.

HTML, CSS, JS
index.html
More precisely, if you are curious

The server checks again. The check in the browser is for the buyer's convenience: they see the mistake right away. It does not protect the shop. novalidate, the Elements panel or a request sent without a browser skip it, so the server checks every field again. The lesson "Untrusted input" explains why.

What is not sent. A field with no name, an unticked checkbox, an unchosen radio button and a field with disabled. A field with readonly is sent: it only cannot be changed. Files (type="file") need method="post" and enctype="multipart/form-data".

How it is sent. With method="get" (the default) the pairs go into the address: /order?name=…&phone=…. With method="post" they are in the body of the request. Either way they are encoded: @ becomes %40, and a space becomes +.

Enter. Enter in a text field sends the form like a click on the submit button, with the same checks.

minlength and a value from code. minlength checks only text that a person typed. A value from the value attribute or from JavaScript passes, even if it is short.

Without checks. formnovalidate on one button sends without checking (say, "Save draft"). form.submit() from JavaScript does not check either and does not fire the submit event, while form.requestSubmit() does everything a click does.

Styling the errors. CSS sees invalid fields with :invalid, and :user-invalid catches them only after a person has touched them. So a field is not red before the buyer has typed anything. The next module is about CSS.

autocomplete. autocomplete="email", "tel", "name", "street-address" tell the browser what to offer from what it remembers. The buyer fills in the checkout with two clicks.

Exercise

The checkout form

Make the checkout form from scratch, with the fields in this order. "Name" (name), required. "Email" (email), a required email. "Phone" (phone), required, a 0 and nine more digits. "City" (city): a drop-down Sofia, Plovdiv, Varna with the values sofia, plovdiv, varna. A group "Delivery" with two radio buttons (delivery): "To the address" (address), chosen at the start, and "To an office" (office). "Note for the courier" (note), on several lines. A checkbox "Wrap as a gift" (gift) with the value yes. A button "Place order".

HTML, CSS, JS
index.html

Test

Test yourself

1. The buyer typed "Iva" into a field <input id="name"> with no name. What does the form send?
2. Two delivery radio buttons have name="courier" and name="office". What happens?
3. The field is <input name="email" type="email" required>, and the buyer typed iva. What does the browser do on "Place order"?
4. Why does the server check the order when the browser has already checked it?
5. A form has <button>Apply the code</button> with no type. What does a click on it do?

Made by Ivo Gergov as part of Evo Tech's campaign for accessible programming education ·