Forms are how websites listen. Every search box, login screen, contact page and checkout is a form. HTML forms give you a rich set of controls with built-in keyboard support and validation, so you can build a lot before writing any JavaScript. This lesson builds on HTML Tables and the attribute rules from HTML Elements and Attributes.
The form element
All the controls in a form sit inside a <form> element. Two attributes decide what happens when the user submits it:
action– the URL that receives the data, usually a server-side script.method– how the data is sent.getadds it to the URL (good for searches you might bookmark);postsends it in the body of the request (use it for anything that changes data or is private, such as sign-ups and passwords).
Processing the data on the server is a separate topic, covered in PHP Forms: GET and POST. In this lesson the examples use a few lines of JavaScript to display the submitted data on the page instead of sending it anywhere.
Labels: the most important part
Every control needs a visible <label>. Connect them by giving the input an id and the label a matching for attribute. The connection means screen readers read the label when the field is focused, and clicking the label puts the cursor in the field – a bigger target that helps everyone on touch screens.
Each control also needs a name. The name is the key the data is sent under; a field without a name is not submitted at all.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Enquiry form</title>
<style>
body { font-family: sans-serif; }
label, legend { font-weight: bold; }
p > label { display: block; }
p { margin: 0.6rem 0; }
output { display: block; margin-top: 1rem; padding: 0.5rem; background: #eef6ee; white-space: pre-line; }
</style>
</head>
<body>
<form>
<p>
<label for="full-name">Full name</label>
<input type="text" id="full-name" name="fullname" autocomplete="name" required>
</p>
<p>
<label for="email">Email</label>
<input type="email" id="email" name="email" autocomplete="email" required>
</p>
<p>
<label for="phone">Mobile number</label>
<input type="tel" id="phone" name="phone" autocomplete="tel">
</p>
<button type="submit">Send enquiry</button>
</form>
<output id="out"></output>
<script>
document.querySelector('form').addEventListener('submit', function (event) {
event.preventDefault();
const data = new FormData(event.target);
let text = 'Submitted data:\n';
for (const [name, value] of data) {
text += name + ' = ' + value + '\n';
}
document.getElementById('out').textContent = text;
});
</script>
</body>
</html>Watch out: A placeholder is not a label. Placeholder text disappears as soon as someone types, often has poor contrast, and is not reliably announced. Use it only for an extra hint, such as an example format.
Input types
The type attribute changes how an <input> behaves. Choosing the right type in HTML forms gives mobile users the right keyboard and gives you free validation.
| Type | Use for |
|---|---|
text | Short free text such as a name |
email | Email addresses; checks the format and shows an @ keyboard on phones |
tel | Phone numbers; shows a number pad (no format check, as formats vary by country) |
password | Passwords; hides the characters |
number | Quantities, with min, max and step |
date | Dates, with a native date picker |
search | Search boxes |
checkbox / radio | Yes/no choices and one-from-many choices |
The autocomplete attribute (for example autocomplete="email") lets browsers fill in saved details, which saves typing and reduces errors.
Choices: radio buttons, checkboxes and select
Radio buttons let the user pick exactly one option. Give every radio in the group the same name and a different value. Checkboxes allow any number of selections. A <select> drop-down is useful when there are many options, and <textarea> accepts several lines of text.
Group related controls in a <fieldset> with a <legend>. The legend acts as a label for the whole group, so a screen reader announces “Room type” before “Single” or “Double”.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Booking form</title>
<style>
body { font-family: sans-serif; }
label, legend { font-weight: bold; }
p > label { display: block; }
p { margin: 0.6rem 0; }
output { display: block; margin-top: 1rem; padding: 0.5rem; background: #eef6ee; white-space: pre-line; }
fieldset { margin-bottom: 0.8rem; }
</style>
</head>
<body>
<form>
<fieldset>
<legend>Room type</legend>
<label><input type="radio" name="room" value="single" required> Single</label>
<label><input type="radio" name="room" value="double"> Double</label>
<label><input type="radio" name="room" value="family"> Family</label>
</fieldset>
<fieldset>
<legend>Extras</legend>
<label><input type="checkbox" name="extras" value="breakfast"> Breakfast</label>
<label><input type="checkbox" name="extras" value="pickup"> Airport pick-up</label>
</fieldset>
<p>
<label for="city">City</label>
<select id="city" name="city">
<option value="">Choose a city</option>
<option value="pondicherry">Pondicherry</option>
<option value="madurai">Madurai</option>
<option value="kochi">Kochi</option>
</select>
</p>
<p>
<label for="notes">Special requests</label>
<textarea id="notes" name="notes" rows="3" cols="30"></textarea>
</p>
<button type="submit">Check availability</button>
</form>
<output id="out"></output>
<script>
document.querySelector('form').addEventListener('submit', function (event) {
event.preventDefault();
const data = new FormData(event.target);
let text = 'Submitted data:\n';
for (const [name, value] of data) {
text += name + ' = ' + value + '\n';
}
document.getElementById('out').textContent = text;
});
</script>
</body>
</html>Tip: Wrapping the input inside its <label>, as with the radio buttons above, is another valid way to connect them. No for or id is needed in that case.
Buttons
Use <button type="submit"> to submit a form. Always state the type: a button inside a form is a submit button by default, which surprises people who meant it for something else. Use type="button" for buttons that run JavaScript, and avoid type="reset", which wipes everything the user typed with one accidental click.
Built-in validation in HTML forms
Browsers can check what people type before the form is submitted, with no JavaScript. Try submitting the form below with empty or wrong values.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Validation</title>
<style>
body { font-family: sans-serif; }
label, legend { font-weight: bold; }
p > label { display: block; }
p { margin: 0.6rem 0; }
output { display: block; margin-top: 1rem; padding: 0.5rem; background: #eef6ee; white-space: pre-line; }
</style>
</head>
<body>
<form>
<p>
<label for="pin">PIN code (6 digits)</label>
<input id="pin" name="pin" inputmode="numeric" pattern="[0-9]{6}" required>
</p>
<p>
<label for="guests">Guests (1–6)</label>
<input type="number" id="guests" name="guests" min="1" max="6" value="2">
</p>
<p>
<label for="pass">Password (at least 8 characters)</label>
<input type="password" id="pass" name="password" minlength="8" autocomplete="new-password" required>
</p>
<button type="submit">Register</button>
</form>
<output id="out"></output>
<script>
document.querySelector('form').addEventListener('submit', function (event) {
event.preventDefault();
const data = new FormData(event.target);
let text = 'Submitted data:\n';
for (const [name, value] of data) {
text += name + ' = ' + value + '\n';
}
document.getElementById('out').textContent = text;
});
</script>
</body>
</html>required– the field cannot be empty.minlength/maxlength– limits on the number of characters.min/max– limits for numbers and dates.pattern– a regular expression the value must match.
Watch out: Browser validation is for convenience only. Anyone can bypass it, so the server must always check the data again. This is covered in PHP Forms: GET and POST.
You can style HTML forms with CSS and add custom behaviour with JavaScript Events. Next, you will learn how to give your whole page a meaningful structure in HTML Semantic Elements.
Further reading
- developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/form
- developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/input
- developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/label
- developer.mozilla.org/en-US/docs/Learn_web_development/Extensions/Forms/Form_validation
- html.spec.whatwg.org/multipage/forms.html
- w3.org/WAI/tutorials/forms
