Forms are how people send information to a website: searches, sign-ups, bookings and payments. HTML forms work without any JavaScript. The browser collects the values, packages them and sends them to a URL, and it handles keyboard use, autofill and validation for you.
A complete form
<!DOCTYPE html>
<html lang="en-GB">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Join the newsletter | Riverside Bakery</title>
</head>
<body>
<h1>Join the newsletter</h1>
<form action="/newsletter" method="post">
<p>
<label for="name">Your name</label>
<input id="name" name="name" type="text">
</p>
<p>
<label for="email">Email address</label>
<input id="email" name="email" type="email" required>
</p>
<button type="submit">Subscribe</button>
</form>
</body>
</html>
The rest of this lesson explains each part.
The form element
form wraps the controls that are submitted together.
actionis the URL that receives the data. If you leave it out, the form submits to the current page's URL.methodis the HTTP method:getorpost. The default isget.
GET or POST?
| Method | Data goes in | Use for |
|---|---|---|
get | The URL: /search?q=rye | Searches and filters, anything safe to bookmark or share |
post | The request body | Anything that creates or changes data: sign-ups, orders, messages |
GET requests can be cached, bookmarked and repeated without side effects. Never use GET for passwords or personal data, because the values appear in the address bar, browser history and server logs.
The input element
input is the most versatile form control. Its type attribute decides what kind of control it is: text, email, password, checkbox, radio, date and many more. The default is text. The next lesson covers the types.
input is a void element, so it has no closing tag. Its current value can be preset with the value attribute:
<input id="town" name="town" type="text" value="Bristol">
The name attribute decides what is sent
When a form submits, the browser sends each control's name with its current value. A control without a name is not submitted at all. This is the most common reason "my form does not send the field".
Fill in the form above with "Sam" and "sam@example.com" and submit it. With method="get", the browser would request:
/newsletter?name=Sam&email=sam%40example.com
With method="post", the same name=value pairs travel in the request body instead. Special characters such as @ and spaces are encoded automatically.
The id and the name do different jobs. id identifies the element in the page, for labels, CSS and JavaScript. name is the key the server receives. They are often the same, but they do not have to be.
To see what a form sends, open DevTools, go to the Network panel, submit the form and click the request. The Payload tab shows every name and value.
Labels
Every control needs a label: visible text that says what to enter. Connect the two with for on the label and the matching id on the control:
<label for="email">Email address</label>
<input id="email" name="email" type="email">
A connected label does three things:
- Screen readers announce "Email address, edit text" when the field receives focus. Without the connection, they announce only "edit text".
- Clicking or tapping the label focuses the field. For checkboxes and radio buttons, it toggles them, which gives a much bigger target.
- Voice control users can say "click Email address".
You can also wrap the control inside the label, with no for or id needed:
<label>
Email address
<input name="email" type="email">
</label>
Both forms work. The for and id version is more flexible for styling and layout.
placeholder is not a label. It disappears when someone starts typing, is often low in contrast, and is not reliably announced by every screen reader. Use a real label, and use the placeholder, if at all, for a short example of the format.
Buttons
button submits the form by default:
<button type="submit">Subscribe</button>
The type attribute has three values:
| Type | What it does |
|---|---|
submit | Submits the form. This is the default inside a form. |
reset | Clears every control back to its initial value. Rarely useful and easy to click by mistake. |
button | Does nothing on its own. Use it for buttons that run JavaScript. |
Always set type explicitly. A button meant to open a menu but left without type="button" will submit the form when clicked.
Pressing Enter in a text field also submits the form. That is expected behaviour, called implicit submission, and it works reliably when the form has a submit button.
You may also see <input type="submit" value="Subscribe">. It works, but button can contain other elements, such as an icon, and is easier to style.
Disabled and read-only
disabledgreys out a control, removes it from the tab order, and does not submit its value.readonlylets people see and select the value but not change it, and the value is submitted.
What the browser does not do
HTML collects and sends data. It does not store anything. Something on the server must receive the request, check the data and act on it: a PHP script, a WordPress plugin, a serverless function or a form service. Always validate on the server too, because anyone can send any data to your action URL, whatever your HTML allows.
Summary
formwraps the controls;actionsets the URL andmethodsets GET or POST.- Use GET for searches and POST for anything that changes data.
- Only controls with a
nameare submitted. - Give every control a visible
labelconnected withforandid. - Set
typeon everybutton, and validate on the server as well as in the browser.