In short
HTML input form attributes like form, formaction, formmethod, formenctype, formtarget and formnovalidate let one field or button change how a form is sent. Learn each with a "Save draft vs Publish" example. What are input form attributes?
HTML input form attributes like form, formaction, formmethod, formenctype, formtarget and formnovalidate let one field or button change how a form is sent. Learn each with a "Save draft vs Publish" example.
What are input form attributes?
So far, all the sending settings lived on the <form> element: action, method, enctype, target and novalidate. But sometimes one form needs two different ways to submit. For example, a blog editor has a "Save draft" button and a "Publish" button. Same fields, different destinations.
HTML has special attributes for this. They go on individual fields and submit buttons:
| Attribute | Goes on | Overrides the form's |
|---|---|---|
form | Any form field or button | Which form it belongs to |
formaction | Submit buttons | action |
formmethod | Submit buttons | method |
formenctype | Submit buttons | enctype |
formtarget | Submit buttons | target |
formnovalidate | Submit buttons | novalidate |
Think of a parcel at the post office. The form attributes are the address printed on the box. The form... button attributes are a sticker that says "this time, send it express to a different address".
"Submit buttons" means a <button type="submit"> (the default type for buttons in a form) or an <input type="submit"> or <input type="image">.
The form attribute: inputs outside a form
Normally a field must be inside the <form> to be sent. The form attribute breaks that rule. Give the form an id, then give the field form="that-id", and the field belongs to the form wherever it is on the page.
This is useful when your layout puts a field far away from its form, such as a search box in the header with its button somewhere else, or a table where each row has its own small form.
<form id="newsletter" action="/subscribe" method="post">
<label for="sub-email">Email address</label>
<input type="email" id="sub-email" name="email" required>
</form>
<aside>
<h2>Choose your topics</h2>
<label><input type="checkbox" name="topics" value="recipes" form="newsletter"> Recipes</label>
<label><input type="checkbox" name="topics" value="events" form="newsletter"> Events</label>
</aside>
<button type="submit" form="newsletter">Subscribe</button>
The checkboxes and the button sit outside the <form>, yet clicking "Subscribe" sends the email and the chosen topics to /subscribe. The form value must exactly match the form's id.
A table with one form per row
You cannot put a <form> around a table row, but the form attribute solves it:
<form id="row-1" action="/cart/update" method="post"></form>
<form id="row-2" action="/cart/update" method="post"></form>
<table>
<tr>
<th>Product</th><th>Quantity</th><th></th>
</tr>
<tr>
<td>Coffee beans 1 kg</td>
<td>
<input type="hidden" name="product" value="beans" form="row-1">
<input type="number" name="qty" value="1" min="0" aria-label="Quantity of coffee beans" form="row-1">
</td>
<td><button type="submit" form="row-1">Update</button></td>
</tr>
<tr>
<td>Paper filters</td>
<td>
<input type="hidden" name="product" value="filters" form="row-2">
<input type="number" name="qty" value="2" min="0" aria-label="Quantity of paper filters" form="row-2">
</td>
<td><button type="submit" form="row-2">Update</button></td>
</tr>
</table>
Each "Update" button only sends the fields from its own row, because each row's fields point to a different empty form.
Common mistake: Typing the
formvalue with a#, likeform="#newsletter". Use just the id:form="newsletter". With a#, the field silently belongs to no form and is not sent.
formaction, formmethod, formenctype and formtarget
These go on a submit button and only apply when that button is clicked.
formactionsends the data to a different URL.formmethodusesgetorpostfor this button.formenctypechanges the encoding, for example tomultipart/form-data.formtargetopens the result somewhere else, like_blankfor a new tab.
<form action="/products/search" method="get">
<label for="product-search">Search products</label>
<input type="search" id="product-search" name="q">
<button type="submit">Search</button>
<button type="submit" formaction="/products/export" formmethod="post" formtarget="_blank">Export results as CSV</button>
</form>
"Search" uses the form's own settings: GET to /products/search in the same tab. "Export results as CSV" sends the same search term with POST to /products/export and opens the result in a new tab.
formnovalidate and the "Save draft vs Publish" example
formnovalidate turns off browser validation for one button. This is perfect for a draft: you want to save unfinished work, even if required fields are still empty. But when you publish, every rule should be checked.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>New Post - Trail Notes Editor</title>
</head>
<body>
<h1>Write a new post</h1>
<form action="/posts/publish" method="post" enctype="multipart/form-data">
<p>
<label for="post-title">Title</label><br>
<input type="text" id="post-title" name="title" required minlength="5" maxlength="100">
</p>
<p>
<label for="post-body">Post</label><br>
<textarea id="post-body" name="body" rows="10" required minlength="200"></textarea>
</p>
<p>
<label for="cover">Cover photo</label><br>
<input type="file" id="cover" name="cover" accept="image/*" required>
</p>
<button type="submit" formaction="/posts/draft" formnovalidate>Save draft</button>
<button type="submit" formaction="/posts/preview" formtarget="_blank" formnovalidate>Preview</button>
<button type="submit">Publish</button>
</form>
</body>
</html>
Here is what each button does:
- Save draft sends everything to
/posts/draftand skips validation, so a half-written post with no cover photo can still be saved. - Preview sends to
/posts/preview, opens it in a new tab and also skips validation, so you can look at your post while you keep writing. - Publish uses the form's own settings: it sends to
/posts/publish, and only after the title is at least 5 characters, the post is at least 200 characters and a cover photo is chosen.
Tip: Put the main action, like "Publish", in a clear position and style it as the primary button. When the user presses Enter in a text field, the browser uses the first submit button in the form, which here is "Save draft". That is a safe default for an editor, but think about which button should come first in your own forms.
Note: The server must still check everything. It should accept incomplete data at
/posts/draftbut refuse it at/posts/publish, because browser checks can always be bypassed. Learn more on MDN: the button element.
Practice exercise
Build a job application form with name, email and a required CV upload. Add three buttons: "Submit application" (normal), "Save and finish later" that sends to /apply/save without validation, and "Print preview" that opens /apply/print in a new tab with GET. Put a "Notes for the recruiter" textarea outside the form and connect it with the form attribute.
Hint: the textarea needs form="your-form-id", and the print button needs formaction, formmethod="get" and formtarget="_blank".
Key takeaways
- The
formattribute connects a field or button to a form by itsid, even outside the form. formaction,formmethod,formenctypeandformtargetoverride the form's settings for one submit button.formnovalidateskips browser validation for one button, perfect for "Save draft".- Pressing Enter uses the first submit button in the form.
- Always validate on the server too.