Building complete HTML forms
A portfolio without a way to get in touch is a missed opportunity. In this lesson you will build a complete contact form: labels, the many types of fields, built-in validation, dropdowns, grouped options and buttons. You will also learn what a form does when it is submitted, and what it cannot do without a server.
What a form is
A form element wraps a set of controls that visitors fill in. When they press the submit button, the browser collects the values and sends them to an address. Two attributes tell it how:
action: the address that will receive the data.method: how the data is sent.getputs the values in the address (suitable for searches),postsends them in the body of the request (suitable for messages and anything private).
<form action="/send-message" method="post">
...
</form>
Labels: the golden rule
Every field needs a label. It tells the visitor what to type, enlarges the click area (clicking the label puts the cursor in the field) and is read aloud by screen readers. There are two equivalent ways to link them:
<label for="name">Your name</label>
<input type="text" id="name" name="name">
<label>Your name <input type="text" name="name"></label>
The first links by matching for and id. The second wraps the field inside the label. A placeholder attribute shows a hint inside an empty field, but it is not a replacement for a label: it disappears when typing, and is often low in contrast.
The input element and its types
The void element input changes behavior based on its type. Choosing the right type gives you proper keyboards on phones, built-in checks and better accessibility for free.
| Type | Use |
|---|---|
text | A single line of text (default) |
email | An email address; checks the format and shows a suitable keyboard |
tel | A phone number |
url | A web address |
password | Hides the characters |
number | A number, with optional min, max and step |
date | A date picker |
checkbox | An option that can be ticked, independently of others |
radio | One choice among several |
file | Upload a file |
search | A search field |
The name attribute is the key under which the value is sent. A field without a name is simply not submitted.
Longer text: textarea
For multi-line messages, use textarea. It has an opening and closing tag, and rows sets its visible height:
<label for="message">Your message</label>
<textarea id="message" name="message" rows="6"></textarea>
Choices: select, checkbox and radio
A dropdown list uses select with option elements:
<label for="topic">Subject</label>
<select id="topic" name="topic">
<option value="">Choose a subject</option>
<option value="portrait">Portrait session</option>
<option value="illustration">Illustration request</option>
<option value="other">Something else</option>
</select>
The value is what gets sent; the text between the tags is what the visitor sees.
Radio buttons let the visitor choose exactly one option. Buttons are tied into a group by sharing the same name:
<fieldset>
<legend>How would you like me to reply?</legend>
<label><input type="radio" name="reply" value="email" checked> By email</label>
<label><input type="radio" name="reply" value="phone"> By phone</label>
</fieldset>
A fieldset groups related controls and its legend gives the group a name. It is especially important for radio buttons and checkboxes, so that screen readers announce the question along with each option. Checkboxes work like radio buttons but allow several to be ticked:
<label><input type="checkbox" name="newsletter" value="yes"> Send me news about new projects</label>
Built-in validation
Browsers can check input before sending, without any JavaScript. You add constraints with attributes:
required: the field must be filled in.minlengthandmaxlength: limits on text length.minandmax: limits for numbers and dates.pattern: a regular expression the value must match.type="email"andtype="url": format checks.
<label for="email">Email address</label>
<input type="email" id="email" name="email" required autocomplete="email">
<label for="subject">Subject (at least 5 characters)</label>
<input type="text" id="subject" name="subject" required minlength="5">
The autocomplete attribute helps the browser pre-fill known information such as name and email, saving people time and effort.
Warning. Browser validation improves the experience but is not security. A determined person can bypass it, so any server that receives the data must check it again. Never trust data only because the form “required” it.
Buttons
The button element triggers an action. Its type matters:
type="submit": sends the form (the default inside a form).type="reset": clears all fields. Rarely helpful, since it can erase work by accident.type="button": does nothing by itself; used with JavaScript.
Use a button for actions and a link for navigation. Write a clear label: “Send message” is better than “Submit”.
What happens when you submit?
With method="post", the browser sends the data to the action address, and something on that server must receive it. HTML alone cannot save a message or send an email. There are several common solutions: a server-side program you write or host, or a form-handling service that gives you an address to put in action. A mailto: action opens the visitor’s email program, but behavior is unreliable and exposes your address, so it is not recommended for a real contact form.
In this course, the form on your portfolio will not be connected to anything yet. That is fine: you are learning the structure, which stays the same whatever service you connect later. If you use a third-party service, read its privacy terms, because you will be collecting personal data from your visitors, and in many countries rules such as the GDPR apply.
A complete contact form
<form action="#" method="post">
<p>
<label for="c-name">Your name</label>
<input type="text" id="c-name" name="name" required autocomplete="name">
</p>
<p>
<label for="c-email">Your email</label>
<input type="email" id="c-email" name="email" required autocomplete="email">
</p>
<p>
<label for="c-topic">Subject</label>
<select id="c-topic" name="topic">
<option value="portrait">Portrait session</option>
<option value="illustration">Illustration request</option>
<option value="other">Something else</option>
</select>
</p>
<p>
<label for="c-message">Your message</label>
<textarea id="c-message" name="message" rows="6" required minlength="10"></textarea>
</p>
<p>
<label><input type="checkbox" name="consent" required> I agree to be contacted about my request</label>
</p>
<button type="submit">Send message</button>
</form>
Wrapping each label-and-field pair in a paragraph is a simple way to stack them without CSS. Later you will use a different wrapper and style it properly.
Tip. Test your form with the keyboard only: press Tab to move between fields, Space to tick a box, Enter to submit. If you can fill and send it without a mouse, you have a more accessible form.
Your turn
- Create
contact.htmlwith your header, nav and footer, and amaincontaining anh1and a form. - Add fields for name, email, subject (a
select), message (textarea) and a consent checkbox, each with a linked label. - Make name, email and message required, and the message at least 10 characters long.
- Add a group of radio buttons in a
fieldsetto choose a preferred reply method. - Submit the empty form and observe the validation messages, then fill it in correctly.
See a solution
Start from the complete form above and add the radio group between the subject and the message:
<fieldset>
<legend>Preferred reply</legend>
<label><input type="radio" name="reply" value="email" checked> Email</label>
<label><input type="radio" name="reply" value="phone"> Phone</label>
</fieldset>
When you submit with an empty required field, the browser blocks the sending and highlights the first problem with a message. Typing something that does not look like an email in the email field gives another message. If nothing happens when you press the button, check that the button is inside the form element and that its type is submit.
Key takeaways
- Every field has a visible
labellinked byforandid(or by wrapping); a placeholder is not a label. - Choose the right
inputtype (email,tel,number,date…) and give each field aname. - Use
select,radio,checkboxandfieldsetwithlegendto offer choices. required,minlength,patternand typed inputs give native validation, which does not replace server checks.- HTML only describes the form: a server or service must receive and process the data.