[javascript] How is the default submit button on an HTML form determined?

If a form is submitted but not by any specific button, such as

  • by pressing Enter
  • using HTMLFormElement.submit() in JS

how is a browser supposed to determine which of multiple submit buttons, if any, to use as the one pressed?

This is significant on two levels:

  • calling an onclick event handler attached to a submit button
  • the data sent back to the web server

My experiments so far have shown that:

  • when pressing Enter, Firefox, Opera and Safari use the first submit button in the form
  • when pressing Enter, IE uses either the first submit button or none at all depending on conditions I haven't been able to figure out
  • all these browsers use none at all for a JS submit

What does the standard say?

If it would help, here's my test code (the PHP is relevant only to my method of testing, not to my question itself)

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
                      "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Test</title>
</head>

<body>

<h1>Get</h1>
<dl>
<?php foreach ($_GET as $k => $v) echo "<dt>$k</dt><dd>$v</dd>"; ?>
</dl>

<h1>Post</h1>
<dl>
<?php foreach ($_POST as $k => $v) echo "<dt>$k</dt><dd>$v</dd>"; ?>
</dl>

<form name="theForm" method="<?php echo isset($_GET['method']) ? $_GET['method'] : 'get'; ?>" action="<?php echo $_SERVER['SCRIPT_NAME']; ?>">
    <input type="text" name="method" />
    <input type="submit" name="action" value="Button 1" onclick="alert('Button 1'); return true" />
    <input type="text" name="stuff" />
    <input type="submit" name="action" value="Button 2" onclick="alert('Button 2'); return true" />
    <input type="button" value="submit" onclick="document.theForm.submit();" />
</form>

</body></html>

This question is related to javascript html cross-browser standards

The answer is


<form onsubmit="alert('submit');return false;">
    <input name="username">
    <input name="password" type="password">
    <button onclick="if(document.activeElement === this){alert('button 1');}else{default_submit.click();}return false;">button 1</button>
    <button onclick="if(document.activeElement === this){alert('button 2');}else{default_submit.click();}return false;">button 2</button>
    <input id="default_submit" type="submit">
</form>

if you press enter from text input, then the button will not focused, then we ignore this click and click the default submit instead, but if you click the button by mouse, it will be focused, then we apply this click


Strange that the first button Enter goes always to the first button regardless is visible or not, e.g. using jquery show/hide(). Adding attribute .attr('disabled', 'disabled') prevent receiving Enter submit button completely. It's problem for example when adjusting Insert/Edit+Delete button visibility in record dialogs. I found less hackish and simple placing Edit in front of Insert

<button type="submit" name="action" value="update">Update</button>
<button type="submit" name="action" value="insert">Insert</button>
<button type="submit" name="action" value="delete">Delete</button>

and use javascript code:

$("#formId button[type='submit'][name='action'][value!='insert']").hide().attr('disabled', 'disabled');
$("#formId button[type='submit'][name='action'][value='insert']").show().removeAttr('disabled');

my recipe:

<form>
<input type=hidden name=action value=login><!-- the magic! -->

<input type=text name=email>
<input type=text name=password>

<input type=submit name=action value=login>
<input type=submit name=action value="forgot password">
</form>

It will send the default hidden field if none of the buttons are 'clicked'.

if they are clicked, they have preference and it's value is passed.


Andrezj's pretty much got it nailed... but here's an easy cross-browser solution.

Take a form like this:

<form>
    <input/>
    <button type="submit" value="some non-default action"/>
    <button type="submit" value="another non-default action"/>
    <button type="submit" value="yet another non-default action"/>

    <button type="submit" value="default action"/>
</form>

and refactor to this:

<form>
    <input/>

    <button style="overflow: visible !important; height: 0 !important; width: 0 !important; margin: 0 !important; border: 0 !important; padding: 0 !important; display: block !important;" type="submit" value="default action"/>

    <button type="submit" value="some non-default action"/>
    <button type="submit" value="another non-default action"/>
    <button type="submit" value="yet another non-default action"/>
    <button type="submit" value="still another non-default action"/>

    <button type="submit" value="default action"/>
</form>

Since the W3C spec indicates multiple submit buttons are valid, but omits guidance as to how the user-agent should handle them, the browser manufacturers are left to implement as they see fit. I've found they'll either submit the first submit button in the form, or submit the next submit button after the form field that currently has focus.

Unfortunately, simply adding a style of display: none; won't work because the W3C spec indicates any hidden element should be excluded from user interactions. So hide it in plain sight instead!

Above is an example of the solution I ended up putting into production. Hitting the enter key triggers the default form submission is behavior as expected, even when other non-default values are present and precede the default submit button in the DOM. Bonus for mouse/keyboard interaction with explicit user inputs while avoiding javascript handlers.

Note: tabbing through the form will not display focus for any visual element yet will still cause the invisible button to be selected. To avoid this issue, simply set tabindex attributes accordingly and omit a tabindex attribute on the invisible submit button. While it may seem out of place to promote these styles to !important, they should prevent any framework or existing button styles from interfering with this fix. Also, those inline styles are definitely poor form, but we're proving concepts here... not writing production code.


From the HTML 4 spec:

If a form contains more than one submit button, only the activated submit button is successful.

This means that given more than 1 submit button and none activated (clicked), none should be successful.

And I'd argue this makes sense: Imagine a huge form with multiple submit-buttons. At the top, there is a "delete this record"-button, then lots of inputs follow and at the bottom there is an "update this record"-button. A user hitting enter while in a field at the bottom of the form would never suspect that he implicitly hits the "delete this record" from the top.

Therefore I think it is not a good idea to use the first or any other button it the user does not define (click) one. Nevertheless, browsers are doing it of course.


HTML 4 does not make it explicit. The current HTML5 working draft specifies that the first submit button must be the default:

A form element's default button is the first submit button in tree order whose form owner is that form element.

If the user agent supports letting the user submit a form implicitly (for example, on some platforms hitting the "enter" key while a text field is focused implicitly submits the form), then doing so for a form whose default button has a defined activation behavior must cause the user agent to run synthetic click activation steps on that default button.


When you have multiple submit buttons in a single form and a user presses the ENTER key to submit the form from a text field, this code overrides default functionality, by calling the submit event on the form from the key press event. Here is that code:

$('form input').keypress(function(e){

    if ((e.which && e.which == 13) || (e.keyCode && e.keyCode == 13)){ $(e.target).closest('form').submit(); return false; }
    else return true;

});

I struggled with the same question since i had submit button in the middle of the from which redirected submit to another page, like so:

<button type="submit" onclick="this.form.action = '#another_page'">More</button>

When user pressed enter key, this button was clicked instead of another submit button.

So i did some primitive tests by creating a from with multiple submit buttons and different visibility options and onclick event alerting which button was clicked: https://jsfiddle.net/aqfy51om/1/

Browsers and OS'es i used for testing:

WINDOWS

  • Google Chrome 43 (c'mon google :D)
  • Mozilla Firefox 38
  • Internet Explorer 11
  • Opera 30.0

OSX

  • Google Chrome 43
  • Safari 7.1.6

Most of these browsers clicked very first button despite the visibility options applied exept IE and Safari which clicked the third button, which is "visible" inside "hidden" container:

<div style="width: 0; height: 0; overflow: hidden;">
    <button type="submit" class="btn btn-default" onclick="alert('Hidden submit button #3 was clicked');">Hidden submit button #3</button>
</div>

So my suggestion, which i'm going to use myself, is:

If you form has multiple submit buttons with different meaning, then include submit button with default action at the beginning of the form which is either:

  1. Fully visible
  2. Wrapped in a container with style="width: 0; height: 0; overflow: hidden;"

EDIT Another option might be to offset the button(still at the beginning of the from) style="position: absolute; left: -9999px; top: -9999px;", just tried it in IE - worked , but i have no idea what else it can screw up, for example printing..


I had a form with 11 submit buttons on it, and it would always use the first submit button when the user pressed enter. I read elsewhere that it is not a good idea (bad practice) to have more than one submit button on a form, and the best way to do this is have the button you want as default, as the only submit button on the form. The other buttons should be made into "TYPE=BUTTON" and an onClick event added that calls your own submit routine in Javascript. Something like this :-

<SCRIPT Language="JavaScript">
function validform()
{
  // do whatever you need to validate the form, and return true or false accordingly
}

function mjsubmit()
{
  if (validform()) { document.form1.submit(); return true;}
  return false;
}
</SCRIPT>
<INPUT TYPE=BUTTON NAME="button1" VALUE="button1" onClick="document.form1.submitvalue='button1'; return mjsubmit();">
<INPUT TYPE=BUTTON NAME="button2" VALUE="button2" onClick="document.form1.submitvalue='button2'; return mjsubmit();">
<INPUT TYPE=SUBMIT NAME="button3" VALUE="button3" onClick="document.form1.submitvalue='button3'; return validform();">
<INPUT TYPE=BUTTON NAME="button4" VALUE="button4" onClick="document.form1.submitvalue='button4'; return mjsubmit();">

Here, button3 is the default, and although you are programmatically submitting the form with the other buttons, the mjsubmit routine validates them. HTH.


This can now be solved using flexbox:

HTML

<form>
    <h1>My Form</h1>
    <label for="text">Input:</label>
    <input type="text" name="text" id="text"/>

    <!-- Put the elements in reverse order -->
    <div class="form-actions">
        <button>Ok</button> <!-- our default action is first -->
        <button>Cancel</button>
    </div>
</form>

CSS

.form-actions {
    display: flex;
    flex-direction: row-reverse; /* reverse the elements inside */
}

Explaination
Using flex box, we can reverse the order of the elements in a container that uses display: flex by also using the CSS rule: flex-direction: row-reverse. This requires no CSS or hidden elements. For older browsers that do not support flexbox, they still get a workable solution but the elements will not be reversed.

Demo
http://codepen.io/Godwin/pen/rLVKjm


EDIT: Sorry, when writing this answer I was thinking about submit buttons in the general sense. The answer below is not about multiple type="submit" buttons, as it leaves only one type="submit" and change the other to type="button". I leave the answer here as reference in case helps someone that can change the type in their form:

To determine what button is pressed when hitting enter, you can mark it up with type="submit", and the other buttons mark them with type="button". For example:

<input type="button" value="Cancel" />
<input type="submit" value="Submit" />

From your comments:

A consequence is that, if you have multiple forms submitting to the same script, you can't rely on submit buttons to distinguish them.

I drop an <input type="hidden" value="form_name" /> into each form.

If submitting with javascript: add submit events to forms, not click events to their buttons. Saavy users don't touch their mouse very often.


Another solution I've used is to just have one button in the form, and fake the other buttons.

Here's an example:

<form>
  <label for="amount">Amount of items</label>
  <input id="amount" type="text" name="amount" />
  <span id="checkStock" class="buttonish">Check stock</span>
  <button type="submit" name="action" value="order">Place order</button>
</form>

I then style the span elements to look like a button. A JS listener observes the span and performs the desired operation once clicked.

Not necessarily right for all situations, but at least it's pretty easy to do.


I think this post would help if someone wants to do it with jQuery:

http://greatwebguy.com/programming/dom/default-html-button-submit-on-enter-with-jquery/

The basic solution is:

$(function() {
    $("form input").keypress(function (e) {
    if ((e.which && e.which == 13) || (e.keyCode && e.keyCode == 13)) {
        $('input[type=submit].default').click();
        return false;
    } else {
        return true;
    }
    });
});

and another I liked was:

jQuery(document).ready(function() {
$("form input, form select").live('keypress', function (e) {
if ($(this).parents('form').find('button[type=submit].default, input[type=submit].default').length <= 0)
return true;

if ((e.which && e.which == 13) || (e.keyCode && e.keyCode == 13)) {
$(this).parents('form').find('button[type=submit].default, input[type=submit].default').click();
return false;
} else {
return true;
}
});
}); 

Examples related to javascript

need to add a class to an element How to make a variable accessible outside a function? Hide Signs that Meteor.js was Used How to create a showdown.js markdown extension Please help me convert this script to a simple image slider Highlight Anchor Links when user manually scrolls? Summing radio input values How to execute an action before close metro app WinJS javascript, for loop defines a dynamic variable name Getting all files in directory with ajax

Examples related to html

Embed ruby within URL : Middleman Blog Please help me convert this script to a simple image slider Generating a list of pages (not posts) without the index file Why there is this "clear" class before footer? Is it possible to change the content HTML5 alert messages? Getting all files in directory with ajax DevTools failed to load SourceMap: Could not load content for chrome-extension How to set width of mat-table column in angular? How to open a link in new tab using angular? ERROR Error: Uncaught (in promise), Cannot match any routes. URL Segment

Examples related to cross-browser

Show datalist labels but submit the actual value Stupid error: Failed to load resource: net::ERR_CACHE_MISS Click to call html How to Detect Browser Back Button event - Cross Browser How can I make window.showmodaldialog work in chrome 37? Cross-browser custom styling for file upload button Flexbox and Internet Explorer 11 (display:flex in <html>?) browser sessionStorage. share between tabs? How to know whether refresh button or browser back button is clicked in Firefox CSS Custom Dropdown Select that works across all browsers IE7+ FF Webkit

Examples related to standards

What are the new features in C++17? Does JSON syntax allow duplicate keys in an object? Use CSS to automatically add 'required field' asterisk to form inputs Is unsigned integer subtraction defined behavior? What is the standard naming convention for html/css ids and classes? Spaces in URLs? Is an anchor tag without the href attribute safe? Set element width or height in Standards Mode What's the difference between __PRETTY_FUNCTION__, __FUNCTION__, __func__? What is the proper declaration of main in C++?