Button Actions

Authors
Alexander Petros (contact@alexpetros.com)
Carson Gross (carson@bigsky.software)
Date Published
April 3, 2026
Last Updated
June 16, 2026
Issue Tracker
WHATWG Issue #12330
Status
Pending
Table of Contents

Summary

Give buttons the action attribute, allowing them to make HTTP requests.

Proposal 2/3 in the Triptych Proposals.

Goals

Proposed Changes

New attributes for the button:

When the action attribute is specified, clicking the button issues an HTTP request to the specified URL. The method attribute can be used to change the HTTP method of the request; it defaults to GET if not specified.

When a button with the action attribute is included inside a form, it does not submit the form. Instead, it makes the request without submitting additional data, exactly the same as if there had been no form at all.

Sample Usage

Logout Button

One of the most common user interactions on the web is logging in or out of a website. A simple POST form, with username and password inputs, can model this interaction.

Logouts, however, do not submit data. There is currently no semantic way to represent a logout button; you have to wrap it in a form. This is one way to do it:

<form action=/logout method=POST>
  <button>Logout</button>
</form>

With support for button actions, we can instead model this as a lone button creating or deleting a "session" resource.Absent PUT, PATCH, and DELETE support, we can instead do <button action=/logout method=POST>Logout</button>, which is also fine.

<button action=/session method=DELETE>Logout</button>
This creates a simplifying symmetry for session management, and allows the logout action to take advantage of DELETE's idempotency. One benefit of this simplification is enabling server frameworks that implement file-based routing (like base PHP, SvelteKit, and NextJS) to implement their authentication entirely within one file. A JS codebase, for instance, might have a sessions.js file, which exports two methods: post and delete. That same file can contain internal helper functions that handle authentication, nicely encapsulating the session management logic and re-using many of the same resources.

Likes and Upvotes

Social sites often let you endorse a piece of content, using a "like" or "upvote." With button actions, this can be trivially implemented with just a URL. HackerNews does this incorrectly: It uses a link, which should only ever trigger safe requests, for the upvote button. It's hard to blame them for this though—the site works without JavaScript, and the workarounds required to use the correct method in HTML are onerous and frustrating. That's what this proposal seeks to fix.

<article>
  <button action="/articles/435/like" method="PUT">⇧</button>
  <span>The Triptych Proposals</span>
</article>

After clicking the button, the server can return an identical page, except the PUT request has been replaced by a DELETE (to delete the upvote). And with Partial Page Replacement, the server can just return a fragment to replace that one article.

Many interactions on the web can be implemented with no request data, just a thoughtful URL structure and the right HTTP method. Web authors benefit tremendously from this pattern. Not only is it simpler, it's easier to audit, because almost all the relevant data can be found in the request logs.

Multi-Action Pages

Consider a simple job application webform, which uses button actions:

<form action="/apply" method="POST">
  <input type="text" name="name">
  <input type="email" name="email">
  <textarea name="coverletter"></textarea>

  <button>Submit</button>
  <button formaction="/draft">Save Draft</button>
  <button action="/" method="GET">Cancel</button>
</form>

The first part of the form is three inputs that the job seeker must fill out: a name, an email, and a cover letter.

The second part is three actions you can take: you can submit the application, save a draft of it, or give up on applying entirely. Each of these buttons interacts with the <form> element differently!

Semantically, each of these buttons represents a reasonable form operation: a user might choose to submit a form, save it as a draft, or cancel it entirely. Without button actions, you can't describe the "Cancel" action correctly. The button element's existing formmethod and formaction methods, which modify the behavior of their containing form, cannot achieve the same "Cancel" experience: using them here would incorrectly navigate to the home page with the form's contents as a query parameter.

You could achieve the same behavior with a link, however, and just style it like a button. That will be discussed further in the existing workarounds section.

Now let's say you save a draft and return to edit it. The web page looks like this:

<form action="/apply" method="POST">
  <input type="text" name="name" value="Alexander Petros">
  <input type="email" name="email" value="contact@example.com">
  <textarea name="coverletter">
    My name is Alex and my passion is enterprise software sales.
  </textarea>

  <button>Submit</button>
  <button formaction="/draft/123" formmethod="PUT">Save Draft</button>
  <button action="/draft/123" method="DELETE">Delete Draft</button>
  <button action="/" method="GET">Cancel</button>
</form>
While the inputs of this form are the same, they have been pre-filled with the current values of the draft job application. This is the essence of Hypertext As the Engine of Application State (HATEOAS). We have also changed one button and added a brand new one.

Once again, all of these buttons are, from the user's perspective, co-equal form controls. But only two of the buttons rely on the form data; two of them do not. Adding buttons that can perform requests independently not only removes the need to wrap them in forms, it also allows for simpler nesting within forms to achieve a complete set of form controls.

Technical Specification

Button actions are a seamless extension of the existing ways to make HTTP requests from HTML. They mimic the semantics of form submission, but with no data.

Enabling Button Actions

To make a request with a button, the action attribute must be specified with a valid URL. The method attribute defaults to GET if not specified; it can also be set to all supported HTTP form methods. At the time of this writing, only GET and POST are supported. With the adoption of Triptych #1, PUT, PATCH, and DELETE would also be supported. In the future, this attribute could include arbitrary custom methods as well.

Buttons can issue requests if they are type=submit, the default button type. submit is a mildly regrettable name in this context, as it is not typically used outside the context of a form (one does not really "submit" a link navigation). It is far more important, however, that the button actions work with the default type, which is and always will be submit, than it is to have a better name for that functionality. Besides, it's far from the most confusing default name in HTML. This is done to both simplify the interface, and align with author expectations that a button with type=submit (or no type specified) is capable of making requests. This document uses the term "author" in the same way that the HTML Design Principles do, to mean the person writing the HTML.

Buttons that have any other type attribute should ignore the method and action attributes.

Interaction with forms

Buttons with the action attribute that are children of a form will not submit any of the form data when clicked.

If the method attribute is specified but no action attribute is, then the method attribute is ignored; the existing formmethod attribute should be used to alter the method of the form.

CORS

Button actions are subject to CORS. All cross-origin requests require a preflight and there are no so-called "simple" cross-origin requests for partial page replacements. Same-origin requests proceed as normal.

This can be accomplished without changes to fetch spec, by adding a non-safelisted header to the request.

The most common question this proposal elicits is "why not just use a link?" For button actions that model GET requests, that is. The reasons you shouldn't use a link for a POST request will be obvious to most people reading this document, but it's worth emphasizing that web authors make this mistake all the time, in part because the wrong thing (using a link) is easier than the right thing (using a button)—fixing that is one of the stated goals of this proposal.

The answer is that links are simply the wrong element for certain user experiences. Buttons and links have different meanings to the user and different behavior in the browser. "The types of actions performed by buttons are distinctly different from the function of a link" - Button Pattern, ARIA Authoring Practices Guide. Web authors who need buttons to correctly model their interface, but are limited by their restricted functionality, are faced with a choice: either add the needed functionality to the button, or try to make links, which do have that functionality, look and behave like buttons.

This section explains why those situations occur and how this proposal closes a small but extremely common gap in their capabilities—one that has led to decades of incorrect, insecure, and inaccessible websites.

Semantic Differences

The W3C's ARIA Authoring Practice Guide (APG) is an authoritative reference for the semantics of HTML elements. It defines a link:

A link widget provides an interactive reference to a resource. The target resource can be either external or local, i.e., either outside or within the current page or application.

And a button:

A button is a widget that enables users to trigger an action or event, such as submitting a form, opening a dialog, canceling an action, or performing a delete operation.

Links represent a place you can go; buttons represent an action you can take. The behavioral differences that arise from these semantics are so baked into our experience of using a web browser that we often don't consciously notice them.

Consider, for instance, the many affordances that browsers offer for opening a link in a new browsing context. A definition of "affordances" from "The Missing Mechanic: Behavioral Affordances as the Limiting Factor in Generalizing HTML Controls" (Petros et al.): In a hypermedia context, affordances are typically discussed in terms of the mechanisms by which the hypermedia user and the hypermedia client interact with one another to achieve the goals of the hypermedia user. In the context of this paragraph, middle-clicking to open a new tab is an affordance; it exists because the authorial intent of a hyperlink is very precise, and the browser can build useful features based on that. A click or tap will navigate the current context to the link's location. Authors can, of course, set the target attribute on the link, but this is much closer to a default than a mandate. Users can still copy the link and open it in the context of their choosing. The link can be opened in a new tab with a middle-click, a click while pressing a modifier key (usually Ctrl or Cmd), or a context menu option, possibly triggered with either a right click or a long press. This feature is likely familiar to anyone who has been on a Wikipedia deep dive. Context menus also make it possible to copy the link's destination to the user's clipboard. Most browsers offer a way to view that destination before navigating to it.

Buttons, however, have none of this functionality. By default, they cannot be middle-clicked, right-click copied, or hovered over for more information. Clicking a button with a modifier key pressed is exactly the same as clicking without one. Their context menus offer no sharing functionality. These are not omissions, but deliberate choices that reflect the button's semantics: a button triggers actions and events inside a fixed browser context. If we were advising web authors when to use buttons instead of links, we would probably substitute "fixed" for "current" in this sentence. The intended audience of this document, however, would reasonably point out that authors can make a form open its response in other contexts, such as a new tab, with target="_blank", or the parent context, with target="_parent". And, of course, the target attribute can be employed to effect changes on an iFrame (used to brilliant effect by htmz), which might be understood by the user as the current context, but is actually a child context.

Therefore, we use the more precise language, even though it's important to call out that the users are overwhelmingingly likely to understand buttons as impacting the "current" context.

The lack of customization afforded by the button illustrates how it serves a complimentary purpose to a link. A link always represents the same action—navigate to a URL—but the user has many options for where that action will take place. A button can represent almost any action—navigate to a URL, open a dialog, delete an item—but the user is not allowed to choose where it takes place.

Notice how "navigate to a URL" is included as a possible result of a clicking a button. Both links and buttons are used in situations where they perform navigations. This section talks about button functionality that is currently only available if the button is associated with a form as if the button were doing it on its own. This is intentional. The section is about what the web user experiences—what they might expect to happen when they click a button and whether this proposal aligns that expectation. In fact, both links and buttons are also used in situations where they don't perform navigations. The following examples are all common experiences on the web:

Navigation Action Non-Navigation Action
Link Go to a new page Scroll to an element
Button Submit a form Open a dialog

All four of these actions are consistent with the semantics we previously established. Both uses of the link bring the user to a destination and both uses of the button take an action within their existing context. Navigation is completely orthogonal to whether an interactive element should be a link or a button.

Not only can buttons trigger full-page navigations, they can do so with both GET and POST requests. Most web users are unfamiliar with HTTP method semantics, but they are accustomed to the idea that clicking a button may or may not result in a "modifying" action. e.g. The "Google Search" button triggers a GET request for the search query and a classic login form will submit a POST request with the user's email and password.

If buttons represent an action the user can take, why would the web author want to be able to implement that action with a page navigation?

First, it needs to be re-emphasized that triggering a page navigation is already a fundamental feature of the button. When you click the login button on a website, you execute a page navigation. What differentiates buttons is that they represent an action that is not available to be re-contextualized by the user; browsers honor this by giving buttons a feature set that doesn't allow for re-contextualization. This is not unlike the reason most programming languages have affordances for private methods and functions. What's the point of having private methods when you could "just not use" the internal methods? Because limiting the scope of the API removes surface area for mistakes and misuse. This is more important in the context of the web than it is in programming libraries because the range of expertise among web users is so much wider. It makes no sense to middle-click a login button—which is why you can't. Consider the counter-factual: middle clicking the button executes the POST login request in a new tab. Now the user has one tab that's logged in and one tab that's not. What benefit does the user get from preserving the old, logged-out tab? Should they expect that clicking links in the logged-out tab will take them to a logged-out or logged-in page? There's no clear answer, and depending on how the website is implemented, it could do either. The capabilities of HTML guide us to experiences that are consistent and match user expectations.

The need for a button that can execute a clean GET navigation (i.e. no query parameter) arises because navigation is the most powerful, most reliable, and most user-friendly primitive that web authors have to change the DOM. Web application largely modeled with page loads are far more predictable and reliable than ones which re-implement these metaphors themselves. When I'm using one of the former, I'm far more confident in the behavior of the "refresh" and "back" buttons, for instance. Web authors can quickly and inexpensively model different states of a web application by breaking it down into discrete pages that are returned by the server. A button that can trigger navigations gives the web author total freedom to change the current web context, without incorrectly communicating to their user that it would make sense for them to copy the link or open it in a new tab.

The web author community has conclusively aligned on the need for a button that can navigate. The official designs systems of the United States and the United Kingdom, which are extensively researched and tested, both contain affordances for adding a "button" class that styles a link to look like a button. This is usa-button and govuk-button, respectively. The UK design system also provides examples of situations in which buttons are appropriate, which include:

Each of these buttons indicates a way for the user to modify the current application context. Not only is page navigation the simplest way to implement that, it's also often the recommended one: the UK Design System's Accessibility Guidelines explicitly encourages a web experience that can work without JavaScript.

Of these four examples, "Sign in" and "Save and continue" can both be implemented with HTML, because they would use a form to submit data. "Start now" and "Continue", however, are both buttons that might be implemented as basic page navigations. With a mandate to support progressive enhancement, HTML buttons can't be used for those, since they don't support basic navigation. Later in the page, a example "Start now" button is shown, which is created with an anchor tag and the govuk-button class. Naturally, the other examples all just use the HTML button tag instead. And indeed, the "Start now" example on that page is a link button.

This practice is often met with an admonishment: buttons should look like buttons and links should look like links. That's true, but it assumes that web authors do this out of ignorance, which is not (always) correct. Making links look like buttons is much more work than using a button; authors do it because buttons lack functionality so important that they are compelled to implement it themselves.

Styling links as buttons is fundamentally inaccessible, but it is the official recommendation of designs systems that prioritize accessibility because it's the only way to implement progressive enhancement.

The MDN page for the ARIA button role contains the following callout:

Warning: Be careful when marking up links with the button role. Buttons are expected to be triggered using the Space or Enter key, while links are expected to be triggered using the Enter key. In other words, when links are used to behave like buttons, adding role="button" alone is not sufficient. It will also be necessary to add a key event handler that listens for the Space key in order to be consistent with native buttons.

Both the US and UK design systems heed the MDN warning and use JavaScript to implement spacebar selection, but spacebar selection is just one of the many ways that buttons behave differently from links. This change took two years to land in the USWDS, by the way. h/t to Jared Cunha for showing me this issue. "Button links" continue to behave like links in most contexts, including, but not limited to, the following:

When web authors style links to look like buttons, they inherit the responsibility to make links behave like buttons in all possible contexts. This is an impossible task. You can intercept middle-clicks with an event handler, but you can't change the system context menu, nor can you override a user's preference for alternative styling.

Web authors face a catch-22: if you need a button to perform a simple navigation in the current context, and you don't want to reply on scripting, you have to use a link, but using a link where you actually need a button introduces accessibility concerns that can only be mitigated with scripting. Even with the best mitigations, using a link button will still misrepresent and mislead the user in contexts you can neither anticipate nor control.

It's good that the browser don't let web pages override user preferences, because that allows them to provide a consistent and secure experience on the web. If, instead, web authors could simply write <button action="/start">, all these problems would disappear and web authors could easily leverage the excellent user experience that web browsers have worked so hard to build.

Partial Page Replacement

Each of the Triptych Proposals stands on its own, but it's worth mentioning that the addition of Partial Page Replacement adds another use for the button that reinforces its existing semantics.

Buttons can trigger many possible effects on the page that aren't navigation, like opening and closing dialogs. Partial page replacement, made available to buttons, would be another non-navigation effect. With a CSS selector provided to the target attribute, activating the button would trigger a network request and change a part of the DOM based on that response.

Adding partial page replacement as a target for the button's action would encourage proper use of buttons by providing a feature exclusive to them. Links would continue to represent destinations that can be independently navigated, while buttons would be able to trigger additional HTTP requests that only make sense within the context of an existing document.

What About Calls to Action?

One does not have to look far to find websites that use button-like styling to emphasize their most important links. These are sometimes called a Call To Action (CTA). For instance, the ARIA APG homepage has many CTAs that look like flat buttons.

A screenshot of the ARIA APG Homepage, which contains the title of the page and explanatory text about the purpose of the APG. It ends with a View Patterns link, which is styled as a white button with rounded corners and black text.
"View Patterns" looks like a button, but it's clear that link behavior is intended—the destination at "View Patterns" is safe to be re-contextualized and, indeed, you can middle-click it.

This proposal does not take a stance on whether it is okay to style your links this way. Although we would advise against it. What we argue is that <a> and <button> have different meanings to the browser and that there are situations in which using a button to perform a fixed-context navigation is unambiguously correct, which is why HTML should support them. Despite looking like buttons, CTAs are not one of those situations.

We have no evidence that lack of support for button actions causes web authors and users to blur the lines between links and buttons, but it would be much easier to promote consistent guidance that "links should always look like links" if there weren't any valid use cases for links that look like buttons.

Existing Workarounds

The previous section is an in-depth explanation of the fundamental principles that make these workarounds invalid. This section has more specifics, but it assumes you've read the previous one.

Unsafe requests

For buttons that would issue GET requests, it is possible to instead use links and style them like a button. This has a couple key problems.

The first is that people often incorrectly use it for unsafe actions. The most famous example of this is the persistent scourge of logout links, which break the entire experience when the browser pre-fetches the link and accidentally logs the user out. This is a very common mistake

<a href=/logout class=button>Logout</a>

The root cause of this mistake is that links issue GET requests to the href URL, but logging out is an unsafe request, which should use a POST request. The recommended solution with current HTML is to create a logout button, wrapped in a form that makes a POST request:

<form action=/logout method=POST>
  <button>Logout</button>
</form>

It's not surprising that people continue to make the logout link mistake, because the recommended solution is more verbose and looks wrong. Why is there a form element when no form data is being submitted? With this proposal, we can have a solution that both looks and is correct.

<button method="POST" action="/logout">Logout</button>

Creating a valid solution that is as simple as a hyperlink will not immediately make people stop using hyperlinks incorrectly, but it will resolve the fact that the platform implicitly discourages their correct use today.

Safe requests

"Link buttons" for safe requests avoid the HTTP semantics problems, but they still have the HTML semantics problems described in Section 5. These manifest as user experience problems as described in Section 5.3

Wrap The Button in a Form

GET forms

As noted above, the recommended way to make buttons perform navigations in HTML is to wrap them in a form.

<form action=/logout method=POST>
  <button>Logout</button>
</form>

Unfortunately, this only works for POST requests. If you do this with a GET request...

<form action=/cancel method=GET>
  <button>Cancel</button>
</form>

... it results in a request to /cancel?, with an extraneous query parameter, which is incorrect. People sometimes argue that having an extraneous ? at the end of your URLs is not a big deal, because severs can "just" ignore the query parameter. This is a faulty assumption. Even though example.com/cancel? and example.com/cancel have the same path, they are not the same URL—one has a query and one doesn't. While many sophisticated routers parse queries into separate objects, this would inhibit the use of HTML for simple server projects and prototypes—exactly where the batteries-included functionality of HTML is most needed.

As noted many times in this proposal, mechanisms that look wrong—and are wrong—go unused by the web author community. This is especially true when the kludge is visible to the user, as it would be in the URL. No authorities recommend using GET forms as a substitute for button links, even with all the compromises those require, because the UX compromises required for GET form navigations are worse.
There is no way to make a button issue a request to URLs that don't end with query parameters in HTML. The need for a button that can make basic navigation requests is described in the "link buttons" section.

POST forms

The form wrapper works for POST requests, but it's still semantically incorrect: there's no form to fill out. Consider the counter-factual: if a colleague used JavaScript to implement a button that makes an HTTP request, would you tell them it's semantically incorrect to use a button this way without wrapping it in a form? No, that's absurd. So then how could requiring an unnecessary form element for request-issuing buttons in HTML possibly be semantically valid? This limitation is not shared by JavaScript, where one can listen for click events on buttons and issue HTTP requests in response; forms play no role in that process. Wrapping buttons in input-less forms is a workaround for missing functionality in HTML.

This technique also cannot be used within forms, for any method. Consider how you might implement Multi-Action Pages with existing native HTML controls:Although still assuming PUT, PATCH, and DELETE support; absent those it's even less clear, because you have to use make both "Save Draft" and "Delete Draft" POSTs, and change the "Delete Draft" URL to something like /draft/123/delete.

<form action="/apply" method="POST">
  <input type="text" name="name" value="Alexander Petros">
  <input type="email" name="email" value="contact@example.com">
  <textarea name="coverletter">
    My name is Alex and my passion is enterprise software sales.
  </textarea>

  <button>Submit</button>
  <button formaction="/draft/123" formmethod="PUT">Save Draft</button>
  <button formmethod="DELETE">Delete Draft<button>
  <a href="/">Cancel</a>
</form>

Here the formmethod attribute has been set to DELETE so the browser (assuming DELETE is supported) will issue a DELETE request to /apply. Unfortunately, this request will include all of the values in the form, which is neither expected nor desired. Another drawback is that the form implementation of DELETE requests will likely use URL query parameters, like GET requests, rather than form-encoded bodies, like POST requests. This means that the URL may be excessively long, and contain leak data that should not have been shared at the URL level.

This limitation only exists in HTML, not the web platform itself. Developers often eschew HTML functionality entirely by describing the UI with buttons and adding the appropriate functionality with scripting. Button actions remove this limitation, allowing HTML to model these form actions both semantically and functionally.

Buttons with Dangling Forms

The HTML standards body recommends that authors model additional actions inside HTML forms by creating additional empty forms elsewhere, then using the form attribute on the button to refer to them. I say "recommends" because this approach was cited by members of the HTML standards committee as a justification for closing the proposal, indicating that this is the blessed approach to achieving this functionality under the current version of the HTML standard. In the above example, this would be a new form specifically for the Delete Draft button that lives below the parent form, because HTML forms cannot be nested.

<form action="/apply" method="POST">
  <input type="text" name="name" value="Alexander Petros">
  <input type="email" name="email" value="contact@example.com">
  <textarea name="coverletter">
    My name is Alex and my passion is enterprise software sales.
  </textarea>

  <button>Submit</button>
  <button formaction="/draft/123" formmethod="PUT">Save Draft</button>
  <button form="delete-form">Delete Draft<button>
  <a href="/">Cancel</a>
</form>

<form id="delete-form" action="/apply" method="DELETE"></form>

This works, but it is a lot more difficult to follow, due to loss of locality. For more on locality, and its importance to HTML specifically, see "Locality of Behaviour." A person editing or auditing this code cannot tell what the button does just by looking at it; they must seek its implementation elsewhere, which, in a real-world scenario, is likely to be quite far away. Notably, this is a problem shared with implementing the button in JavaScript! This complicated and error-prone method clearly does not scale beyond just a few buttons.

Extensive use of this pattern creates the conditions for a surprising XSS vulnerability. If an attacker can inject a form elsewhere in the page, it can control the action of that button.

<form id="delete-form" action="https://evil-url.example.com" method="POST"></form>

This XSS vulnerability is especially dangerous because it allows an attacker to alter a trusted part of the page, even without scripting enabled. Many of the traditional defense-in-depth mechanisms, which focus on limiting sources of scripting, would not catch this.

With the introduction of button actions, HTML can encourage a simpler, more secure pattern:

<button action="/apply" method="DELETE">Delete Draft<button>

A web service with the same security policies, but using a button action, would not be vulnerable to having one of its page controls hijacked by an un-sanitized form, because its behavior is defined entirely within itself. If the web service does sanitize buttons and inputs, but not forms, then it's fine; if it doesn't, the worst an attacker could do is create a new form submission, which would appear in whichever part of the page is displaying user-generated content. That's still bad, but not as bad as hijacking a trusted page control.

Critical mistakes happen when an implementation is too complex to audit or understand. By creating a blessed pattern where buttons can properly define their own functionality, HTML can encourage more secure development patterns with less possibility for error.

Finally, if this solution is sufficient, why is it vanishingly rare? On the WHATWG issue, one commenter who does make use of this pattern noted that it has multiple drawbacks and endorsed the proposal. Why do authors continue to use links for buttons or add "navigate" effects to them with JavaScript, with all the difficulties those cause? Creating an additional, separate, and empty form element for every standalone button action is so impractical, and scales so poorly, that even the most dedicated HTML authors and accessibility testers would hesitate to recommend it for general use. I don't even do that, and I care enough about about HTML to have written all this. -Alex As a result, it has consistently failed to mitigate the problems this proposal seeks to resolve.

Alternatives

Allow name and value

It's possible to let lone buttons submit a single datum, using the name and value attributes. htmx's hx-vals attribute is a more expansive take on this concept, where the values are encoded as JSON in the attribute value.
<button
  action=/members
  method=POST
  name=person
  value=Alex
  >Signup
</button>

This is a reasonable thing to add, and would fit well within the existing semantics of the button, which can have values that get submitted along with their parent form.

It is left out of the main proposal, however, in order to curtail scope. Most of the use-cases for this can also be accomplished with URLs and query parameters.

Buttons with form=_self

Michael West proposed a workaround where buttons would get a _self keyword to use with the form attribute. This proposal neatly sidesteps sanitization questions by not introducing any new elements.

<button form="_self" formaction="/logout" formmethod="post">Logout</button>

Unfortunately, this would not achieve the goals of the proposal. Quite simply, people would not use it.

To start, _self forms still have the query parameter problem. They cannot make clean GET requests, so they would not end the proliferation of "link buttons".

Even in the cases where it does work, the semantics are still confusing. This proposal aims to simplify using buttons outside the context of a form; requiring that that buttons use three form* attributes to take non-form actions is confusing and counterproductive.

Ostensibly, this alternative allows for an elegant HTML-only polyfill, using with a single dangling form:

<form id="_self"></form>

The simplicity of the polyfill also demonstrates why this alternative doesn't accomplish anything. Authors who want to write HTML this way can already include a dangling form at the top of all their documents, but the HTML you end up writing is just as cumbersome as the existing workarounds; if it wasn't, experts would recommend this pattern today. Now that you know you can add <form id="_self"><form> to the top of your document and write all buttons this way, are you going to? Can you imagine writing a beginner's guide to HTML that recommends this practice? The benefit of adding it to HTML is negligible.

Another goal, building a simple metaphor for partial page replacement, becomes prohibitively verbose if you run it entirely through the form semantics.

<button form="_self" formaction="/next" formmethod="get" formtarget="#articles">Logout</button>

Authors reach for alternative solutions when those solutions are more expressive than what the platform provides. HTML is an extremely expressive language—links just happen to be much more expressive than buttons in situations where buttons should be used. An enhancement which doesn't correct this imbalance does not meet the goals of this proposal: to introduce syntax that authors actually want to use.

Use a different name besides "action"

The action attribute was chosen to conform with existing HTML grammar, but lots of names would work. "Action" has always been a somewhat strange choice for that noun, anyway. It makes sense when you consider it—what resource is the button "acting" on?—but it's not really a term that people use for URLs in any other context. Plausible alternatives include: href, url, dest, and location.

<button location="/logout" method="post">Logout</button>

The choice of a new name succeeds where the form* methods fail because they create a syntax that plainly states what the button does, without semantic kludges that push the user away. This is something that would be easy to teach people how to use instead of a link.

This would resolve a concern raised by the standards committee that using action on buttons might have web compatibility problems. It would be helpful to know exactly what adding action to the button is incompatible with. This would assist us in designing a version of this proposal that doesn't have compatibility concerns! Evidently formaction was originally supposed to be called action, and the name was changed to formaction for this reason. This is a better name anyway. The button's formaction method alters the action of its parent form. The name action makes more sense when it refers to its own element's action, just like it does with the form, and, if this proposal were to be adopted, the button.

Footnotes