<form> Form
Wraps the controls whose values get sent to a server.
<form> wraps the inputs, labels and buttons that collect data. On submit, the browser sends each control's name and value to the URL in action, using the method. With get the data goes into the URL, which suits searches. With post it travels in the request body, the right choice for anything private or anything that changes data.
A control without a name is not sent at all. This trips people up constantly. Forms cannot be nested, and built-in validation runs before submission unless you set novalidate.
action, method, enctype and novalidate are covered in the form element in the HTML Living Standard (opens in a new tab). Start with the Forms and Inputs lesson.
Syntax
<form action="/path" method="post">
<label for="field">Label</label>
<input id="field" name="field">
<button>Send</button>
</form>When to use it
Any time people send you information, wrap it in a <form>. Search boxes, newsletter sign-ups, checkouts and settings pages all count. Even if JavaScript processes the data, the form element gets you submit-on-Enter and built-in validation for free, and the page keeps working when the script fails to load.
The server decides the method. Searches and product filters use get, which gives the result page a URL people can bookmark and share. Logins, payments and anything else that creates or changes data use post. And if the only goal is to send someone to another page, that is a plain link. A form with one button is the wrong tool.
File uploads trip people up. With the default encoding the server gets the file name and no file. You need enctype="multipart/form-data" plus method="post". One more thing: a control can belong to a form it is not inside. Set its form attribute to the form's id, which comes in handy when the layout puts a button far from the fields.
Attributes
| Attribute | What it does |
|---|---|
action | URL that receives the data. |
method | get (default) or post. dialog closes a parent dialog. |
enctype | Encoding of the data; multipart/form-data is needed for file uploads. |
name | Name of the form. |
novalidate | Skips built-in validation on submit. |
autocomplete | on or off for the whole form. |
target | Where to show the response, such as _blank. |
Live example
Edit the code and watch the preview.
<form action="/subscribe" method="post">
<label for="email">Email</label>
<input type="email" id="email" name="email" required>
<button type="submit">Subscribe</button>
</form>More examples
Search with GET
This recipe search uses method="get". The query and sort order land in the results page URL, ready to bookmark or paste into a message. A search element wraps the form. Submit it in the preview and look at the data.
<search>
<form action="/search" method="get">
<label for="q">Search recipes</label>
<input type="search" id="q" name="q" required>
<label for="sort">Sort by</label>
<select id="sort" name="sort">
<option value="new">Newest</option>
<option value="popular">Most popular</option>
</select>
<button>Search</button>
</form>
</search>Uploading a photo
For a file to arrive, the form needs method="post" and enctype="multipart/form-data". Leave them off and the server sees the file name only. accept limits the file picker to images, and required blocks sending the form with no photo attached.
<form action="/upload" method="post" enctype="multipart/form-data">
<label for="title">Photo title</label>
<input id="title" name="title" required>
<label for="photo">Photo</label>
<input type="file" id="photo" name="photo" accept="image/*" required>
<button>Upload</button>
</form>Tip: A control without a name never gets its value sent.
Browser support
form works in every browser and is in the HTML Living Standard. All current browsers run the built-in constraint validation that checks required, pattern and similar attributes before sending (see form validation support (opens in a new tab)). Validate on the server as well. Anyone with dev tools can get past the browser's checks.
Accessibility
Label every control and show errors as text next to the field. Placeholder text and color are not enough on their own (WCAG 3.3.1, 3.3.2). Labels, grouping and notifications are all in the W3C forms tutorial (opens in a new tab).
Common mistakes
Wrong
<form>
<input type="email" placeholder="Email">
</form>Right
<form action="/subscribe" method="post">
<label for="email">Email</label>
<input id="email" name="email" type="email" autocomplete="email" required>
<button>Subscribe</button>
</form>It needs a name to be sent, a label for accessibility and a button to submit the form.
Frequently asked questions
What is the difference between GET and POST in forms?
Where the data goes. With method="get", the default, form data is appended to the URL as a query string. That suits searches and filters people might bookmark or share. With method="post" the data travels in the request body, the right choice for sign-ups, orders, uploads and anything else that changes data on the server. Neither method encrypts anything; HTTPS does that. Both methods are defined in RFC 9110, HTTP Semantics (opens in a new tab).
Why is my form input not submitted?
Most likely it has no name. Only named controls go into the submitted data, and an input without one is skipped without any warning. Disabled controls are left out too. Also check that the control sits inside the <form> or is linked to it with the form attribute, and that the action URL is right. An accessible input generator (opens in a new tab) can produce inputs with the correct name and validation attributes.
Practise it
- Forms and Inputs (Module 6: Forms)
- Labels (Module 6: Forms)
- Input Types (Module 6: Forms)
- Textarea, Select, Radio, Checkbox (Module 6: Forms)
- Buttons and Fieldsets (Module 6: Forms)
- Built-in Validation (Module 6: Forms)