The form attribute

You probably know about the <form> element, but did you know there is also an form attribute?

I often said in the past, a <button> outside a form is useless without JavaScript. This is not true, I now know since I learned about the form attribute. Therefore, the corrected version is: a button not associated with a form is useless without JavaScript.

So, what is the form attribute?

It allows you to reference a specific <form> by its ID on an <button> or <input>. Let's see how to use it.

<form id="myform" action="/whatever/">

<!-- Somewhere else in the DOM -->
<button form="myform" formaction="/someaction" formmethod="POST">Action 1</button>
<button form="myform" formaction="/anotheraction" formmethod="POST">Action two</button>
<input type="submit">Whatever</input>

If you click on the Action 1 button if will send a POST request to "/someaction" and if you use the Action 2 button POST request to "/anotheraction". Using the Whatever button will send a GET request to "/whatever". The great thing about forms, they require no JavaScript.

Enhance #

Speaking of JavaScript, you can of course enhance that to send and receive the data with JavaScript.

document.querySelector('#myform').addEventListener('submit', async (e) => {
const action = e.submitter.formAction; // is "" by default, or the action defined for the associated form, or the formaction attribute
const method = e.submitter.formMethod; // is GET by default, or the method defined for the associated form, or the formmethod attribute

let response = await fetch(action, {
method: method,
body: new FormData(e.target)
});

let result = await response.json();
// Handle result and update UI

// Always use preventDefault(); at the end, so if something fails the form gets send server-side
e.preventDefault();
});

Yes, this will not work in browser not supporting async or fetch, but we don't have to worry about it, because the form will still be sent in these browsers, just server-side.

Use cases #

Styling #

Sometimes you may want to place the submit <button> or <input> outside the <form> element, because for whatever reason this may make the styling easier for you. I haven't had such a case yet, but it is still good to know that it is possible.

Multiple single field forms #

Another use case is if you have lots of "single field forms". By single field forms, I mean e.g. the retweet and like button on Twitter. Instead of wrapping these <button> every time in a <form> element you can define the <form> once and use the formaction and formmethod attributes on every <button>.

<!-- define once -->
<form id="myform" method="POST">

<!-- use at the end of every tweet -->
<button form="myform" formaction="/retweet/1270696838778302464">Retweet</button>
<button form="myform" formaction="/like/1270696838778302464">Like</button>

Browser support #

It is currently supported in all modern browsers, however it is not in Internet Explorer. So, if you want to support that browser, you should stick to wrapping all in an extra form.

Resources #

MDN: The input element
MDN: The button element
HTML Living Standard - form attribute
HTML5 - form attribute