skip to content

JavaScript: Preventing Double Form Submission

 Tweet Share0 Tweets

If you've been in the webmaster world for a while then you'll know that your users operate according to Sod's Law - "If anything can go wrong, it will". This page addresses one of the less common, but still quite annoying problems, double-clickers.

A quick double-click on a button or link can have unintended consequences, such as a form being submitted twice, or a script running in parallel to itself and encountering race conditions.

Disabling the Submit Button

In this example, you can click the first button as many times as you want. In practice this can cause a form to be submitted, or some other event triggered, more than once. The second button however will only accept a single click and ignore all subsequent clicks.

The trick is to use JavaScript to set the disabled property of the button to true. The disabled property was first introduced by Microsoft but has since been adopted as a standard by the W3C.

For a simple form, with no associated JavaScripts, you can use:

<form method="POST" action="..." onsubmit="myButton.disabled = true; return true;"> ... <input type="submit" name="myButton" value="Submit"> </form>

So when the form is submitted - either by clicking on the submit button or pressing Enter in a text input field - the submit button will be disabled to prevent double-clicking.

If you're already using JavaScript form validation then the command can instead be added to the script as follows:

<form method="POST" action="..." onsubmit="return checkForm(this);"> ... <input type="submit" name="myButton" value="Submit"> </form> <script type="text/javascript"> function checkForm(form) { // // validate form fields // form.myButton.disabled = true; return true; } </script>

It's important that the command to disable the button be added at the end of the script, otherwise, if the validation fails, the user will have no opportunity to re-submit the form.

Using the above code, after the form has been submitted, if the user clicks the browser Back button then the submit button remains disabled. If you don't want this, read on for some work-arounds.

More User-Friendly

Rather than simply disabling the button, we can also change the text so that people don't get confused. This example first disables the button and then changes the label from "Submit" to "Please wait...". The second button restores the initial state:

The code executed when the form is submitted includes the following:

<script type="text/javascript"> function checkForm(form) // Submit button clicked { // // check form input values // form.myButton.disabled = true; form.myButton.value = "Please wait..."; return true; } function resetForm(form) // Reset button clicked { form.myButton.disabled = false; form.myButton.value = "Submit"; } </script>

While the HTML for the form itself looks something like:

<form method="POST" action="..." onsubmit="return checkForm(this);"> ... <input type="submit" name="myButton" value="Submit"> <input type="button" value="Reset Button" onclick="resetForm(this.form);"> </form>

A triple-click solution

In this slightly more elegant solution the Submit button in this case cycles through three separate states:

  1. the button is active and clickable and will submit the form;
  2. the button is clickable, but will generate an alert message; and
  3. the button is disabled.

In the default state, clicking on the Submit button will call our form validation script (see below) to make sure that all the fields have been populated. If that is not the case then there is an alert message and the script halts.

If/when the form is successfully validated, the button text is changed to "Submitting form..." and a JavaScript variable, submitting is set to true indicating that the form submission is in progress.

A second click on the Submit button before the form has finished submitting will generate an alert message, and also disable the button preventing subsequent clicks. The difference from previous examples is the alert when the button is being disabled.

Triple-click example

Our form validation script in this case simply checks that a value has been entered in each of the two form fields. This function is called from an onsubmit event handler attached so it's called only after any HTML5 form validation requirements have been met.

To test, click the Submit button twice in quick succession. On the second click an alert window will be displayed, while the form continues submitting (from the first click) in the background.

<script type="text/javascript"> var form_being_submitted = false; // global variable function checkForm(form) { if(form.firstname.value == "") { alert("Please enter your first and last names"); form.firstname.focus(); return false; } if(form.lastname.value == "") { alert("Please enter your first and last names"); form.lastname.focus(); return false; } return true; } function resetForm(form) { form.myButton.disabled = false; form.myButton.value = "Submit"; form_being_submitted = false; } </script>

In the HTML for the form the onsubmit handler first checks to see whether the form is already in the process of submitting (second click). If so it displays an alert and disables the submit button to prevent further attempts to submit the form.

If the form is not already being submitted (first click) the handler runs the usual JavaScript validation and, if successful, allows the form to be submitted.

<form method="POST" action="..." onsubmit=" if(form_being_submitted) { alert('The form is being submitted, please wait a moment...'); myButton.disabled = true; return false; } if(checkForm(this)) { myButton.value = 'Submitting form...'; form_being_submitted = true; return true; } return false; "> ... <p>First Name: <input type="text" size="32" required name="firstname"></p> <p>Last Name: <input type="text" size="32" required name="lastname"></p> <p><input type="submit" name="myButton"> <input type="button" value="Reset Button" onclick="resetForm(this.form);"></p> </form>

The Reset button and script are just copied from the previous example, with the one addition being that the form_being_submitted variable is also reset back to false.

For an explanation of the required attribute see our article on HTML5 Form Validation.

Using External JavaScript

We're not changing any of the functionality here, just preparing the JavaScript so it can be moved to an external JavaScript file, and doing away with the necessity for global variables.

First, we strip out any event handlers from the HTML, and assign id values to the elements needing event listeners.

<form id="test_form" method="POST" action="..."> <p>First Name: <input type="text" size="32" required name="firstname"></p> <p>Last Name: <input type="text" size="32" required name="lastname"></p> <p><input type="submit" name="submit_button"> <input id="reset_button" type="button" value="Reset Button"></p> </form>

Note that there is no need to assign an id to all the form elements. Only those with event handlers, and even then we could make do with only the FORM having an id if we wanted.

The next step is to define and assign our event handling functions. The main difference here is that each function receives a variable e representing the event, from which e.target can be used to identify which element was targeted.

And in the form validation script instead of return false; we use e.preventDefault(); which prevents the form from submitting, and then return; to exit the script. There is no need for a return true; at the end.

Finally, we wrap all the code in a DOMContentLoaded function allowing us to create variables without them becoming global. This also delays the script initialisation until the HTML is fully loaded.

<script type="text/javascript"> window.addEventListener("DOMContentLoaded", function(e) { var form_being_submitted = false; var checkForm = function(e) { var form = e.target; if(form_being_submitted) { alert("The form is being submitted, please wait a moment..."); form.submit_button.disabled = true; e.preventDefault(); return; } if(form.firstname.value == "") { alert("Please enter your First Name"); form.firstname.focus(); e.preventDefault(); return; } if(form.lastname.value == "") { alert("Please enter your Last Name"); form.lastname.focus(); e.preventDefault(); return; } form.submit_button.value = "Submitting form..."; form_being_submitted = true; }; var resetForm = function(e) { var form = e.target.form; form.submit_button.disabled = false; form.submit_button.value = "Submit"; form_being_submitted = false; }; document.getElementById("test_form").addEventListener("submit", checkForm, false); document.getElementById("reset_button").addEventListener("click", resetForm, false); }, false); </script>

The JavaScript can now be included either inline on the page, or in a separate JavaScript file referenced by the SCRIPT tag, and it will not interfere with any other scripts on the page because the event listener creates a closure and the contained functions are all defined as local variables.

If you plan to include the JavaScript inline, then instead of using a DOMContentLoaded event handler you can use an IIFE (Immediately Invokable Function Expression) as follows:

(function() { var form_being_submitted = false; var checkForm = function(e) { ... }; var resetForm = function(e) { ... }; document.getElementById("test_form").addEventListener("submit", checkForm, false); document.getElementById("reset_button").addEventListener("click", resetForm, false); })();

In this case the code needs to be place inline anywhere after the FORM - usually at the bottom of the page before the closing BODY tag. It can't be made external or it might execute before the DOM is ready for the event handlers to be assigned.

Preventing double-clicks on links

While the standards suggest that a normal HREF link shouldn't trigger any action other than navigation, it is often the case that links do trigger an action, and the same problems can arise from people double-clicking.

A quick fix for this is to add an onclick handler to the links that disables it for subsequent clicks:

<script type="text/javascript"> function clickStopper(e) { alert("click was blocked"); // ** you can remove this line ** e.preventDefault(); // equivalent to 'return false' } </script> <p><a href="#target" onclick=" this.addEventListener('click', clickStopper, false); ">click me</a></p>

Working Demonstration

In this scenario the first click on the link will function normally taking the user to the target href. At the same time it adds a new event listener to capture and disable future clicks on the same link.

This example should work in Internet Explorer 9 and higher, and can be made to work in earlier versions with a polyfill for event handling.

References

< JavaScript

Send a message to The Art of Web:


used only for us to reply, and to display your gravatar.

<- copy the digits from the image into this box

press <Esc> or click outside this box to close

User Comments

Post your comment or question

24 November, 2016

What is the HTML (or related) standard behavior expected for the browser if the user makes double click on a submit button? I'm seeing that IE11 process a double click as only one click but Google Chrome interprets double click as two submit operations actually.

A click on the submit button submits the form, but depending on your browser and connection speed the window of opportunity for a second click can vary from milliseconds to seconds. Some modern browsers may also have taken measures to prevent duplicate submission.

The reason to use JavaScript is that it disables the submit button instantaneously. A system of single-use client/server tokens can do this as well if you want to avoid relying on JavaScript.

26 June, 2014

Hi, I use Fast Secure Contact Form and I like your second solution. BUT, Where I applied? I'm a really noob. Can you explain where I cut/paste your code? I have some field validation, can I disable submit button after all validations are OK?

12 June, 2014

this doesn't work in Chrome.... fyi.. disabling a submit button stops form submittal

The examples definitely work in Chrome.

24 August, 2013

This is a good solution, HOWEVER, it doesn't really stand well in 2013. It isn't really compatible with HTML5's input "required" attribute. If an input has the required tag, and you press the submit buton, and the field is empty the browser will fire the "Please fill out this field" message, BUT, you also just disabled that submit button. So in effect, the form can no longer be submitted.

This below solution works,

For instance, here is the text input:
<input type="text" id="first_name" required />

Using the 3. A triple-click solution solution above, the submit buton needs an id assigned, in addition to the name:
<input type="submit" name="myButton" id="myButton" onclick="

And this jQuery script is need for EVERY input with the required tag:

document.getElementById('first_name').addEventListener('invalid', function() {
submitting = false;
document.getElementById('myButton').value='Submit';
}, false);

You're right. The solution is to remove the onclick event handler from the submit button and replace it with an onsubmit handler on the form, as we've done now.

20 April, 2013

The disabled state hangs in FF if you use the backbutton. Try clicking button 2 in the first example, visit another page and navigate back via the backbutton. Button 2 is still disabled.

14 June, 2012

thanks dude, the third one sure saved me

23 February, 2008

I am trying to make this work with a page that has JS Code for validation. I placed this at the end of the script. It disabled the button, but the other validation does not work. I know I have missed a step.

I think you need to first read the JavaScript Form Validation article. You seem to have pasted the 'double submit' code outside of any function, so it's being called when the page loads instead of only during form validation.

top