Complete HTML Course Module 7: Intermediate: HTML Forms

HTML Input Form Attributes: form, formaction, formmethod and formnovalidate

  • Beginner
  • Lesson 7.5
  • 5 min read
  • 34 of 69 in the course

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:

AttributeGoes onOverrides the form's
formAny form field or buttonWhich form it belongs to
formactionSubmit buttonsaction
formmethodSubmit buttonsmethod
formenctypeSubmit buttonsenctype
formtargetSubmit buttonstarget
formnovalidateSubmit buttonsnovalidate

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 form value with a #, like form="#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.

  • formaction sends the data to a different URL.
  • formmethod uses get or post for this button.
  • formenctype changes the encoding, for example to multipart/form-data.
  • formtarget opens the result somewhere else, like _blank for 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/draft and 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/draft but 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 form attribute connects a field or button to a form by its id, even outside the form.
  • formaction, formmethod, formenctype and formtarget override the form's settings for one submit button.
  • formnovalidate skips 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.