Forms and inputs
Collecting something from a visitor: the elements that make a form usable, the labels that make it accessible, and the attributes that catch mistakes before they are sent.
A form is a group of controls
A <form> wraps the controls that belong together and says where they would be sent. In this playground nothing is sent anywhere — the preview is a sandbox and there is no server behind it — but the markup is the same one a real page uses, and action and method are how you would point it at one. The method also decides how the values travel: get puts them in the address, post puts them in the request body.
Inside it, the controls you will use most: <input> (which changes completely depending on its type), <textarea> for multi-line text, <select> with <option> children, and <button> to submit.
The attributes that matter
type— text, email, password, number, date, checkbox, radio, file. The browser validates some of them and phones show the right keyboard.name— the key this value arrives under. A control with no name is not submitted at all.value— the starting value.id+<label for="…">— connects a label to a control. Clicking the label focuses the control; a screen reader reads the label as its name.required,minlength,pattern,min/max— constraints the browser checks before submitting.placeholder— a hint that disappears as soon as anything is typed. It is not a label.
Group the questions
<fieldset> draws a box around a group of controls and <legend> gives that box its name. The pair is for a set of answers to one question — a delivery choice, a set of contact preferences — not for every three fields on a form. A screen reader announces the legend before each control inside it, which is what keeps a radio button from arriving with no question attached.
A radio group needs the same name on every option; that shared name is what makes the browser treat them as one choice. Checkboxes do not need it, because each one is its own yes or no. The difference is in the markup, not in how they look.
A form with labels
Give every input a label, and add a submit button at the end.
2 left to do
- There is a form element
- There are at least three labels
- There is a submit button
Either <label for="email">Email</label> with id="email" on the input, or wrap the input inside the label.
Labels are not optional
A placeholder is not a label: it vanishes the moment someone types, it is usually too quiet to read, and it disappears entirely for anyone using a screen reader once the field has a value. Every control needs a name that stays put — either <label for> pointing at the control’s id, or a <label> wrapped around the control itself.
A worked comparison makes the rule concrete. <label for="email">Email</label><input id="email" name="email"> gives the field a name that stays visible, and clicking the word focuses the box. <input name="email" placeholder="Email"> shows the same word until someone types, then shows nothing; a screen reader may read it as a hint, and the field has no name of its own. The first survives a filled-in form; the second does not.
When two controls are alternatives — newsletter yes or no — they belong to a group with a shared question. <fieldset> and <legend> give that question a home.
Catch the mistakes early
Make the email required, and require the password to be at least eight characters.
2 left to do
- Some input is marked required
- An input sets a minimum length
required needs no value. The length rule is minlength="8".
Buttons are controls too
A <button> inside a form submits it unless you say type="button". That default is a common surprise: a button added to open a panel submits the form and reloads the page before the panel can appear. Say what each button does — submit, reset or button — and the behaviour stops being an accident.
The words inside the button are its name. An icon-only button needs a name another way, and aria-label is the attribute for it; a button whose only content is a symbol is announced as that symbol. The same rule as a link: the thing a person clicks should say what it does.
What the browser checks before it sends
The constraints in the markup are checked at submit time, in the page, before anything leaves. required refuses an empty field; type="email" wants something shaped like an address and, on a phone, asks for a keyboard with an @ key; minlength counts characters; pattern matches a regular expression. The browser stops the submission and shows its own message beside the first field that failed. That is useful, but it is a courtesy, not a guarantee: the page can be saved and edited, and a request can be sent by something that never loaded the form, so the server checks again.
Three form mistakes that are invisible until someone tries to use the form: an input with no name, which is never submitted; a label that is not connected to its field, so clicking it does nothing and the field has no spoken name; and a placeholder standing in for a label, which vanishes as soon as typing starts. Check that for and id match, letter for letter.
Try these next
- Group three radio buttons under one
<fieldset>and<legend>, then tab through them. - Add a
type="button"button to a form and confirm it does not submit. - Give an icon-only button an
aria-labeland read it in a screen reader’s element list.
Client-side validation is for the person filling the form in, not for safety. Anything arriving at a server has to be checked again there — but a browser that says "enter a valid email address" before a round trip is a kindness.
Check what you learned
One question at a time. A wrong answer explains itself — take another go.
Part 1 of 5
What happens to an input with no name when a form is submitted?
