Earlier this week I was helping a colleague write some vanilla JavaScript to prevent a form from being submitted multiple times by an overzealous button clicker. The solution needed to be some framework-free JavaScript code. Thankfully this is pretty simple to do, so I thought I’d share some of the options here.
The example code included below is aimed at modern browsers (a minimum of IE10), but I’ve included comments for those needing IE9 support or lower. It’s depressing that in 2017 we’re still having to consider browsers from over five years ago, but sometimes this is necessary. If in doubt about browser support I’d recommend consulting the MDN website.
Disable the Submit Button
The simplest thing to do is disable the submit button the first time the form is submitted so the button cannot be clicked again. We do this by listening for the form being submitted using addEventListener
and then adding the disabled
attribute to the form’s submit button:-
var form = document.querySelector('form');
form.addEventListener('submit', function() {
this.querySelector('input[type="submit"]')
.setAttribute('disabled', 'disabled');
}, false);
For old versions of IE before version 9 you’ll need to use attachEvent
as a fallback for addEventListener
; see Legacy Internet Explorer and attachEvent on the MDN website for further details.
If the form has multiple submit buttons we’d need to use querySelectorAll
to disable all of them:-
var form = document.querySelector('form');
form.addEventListener('submit', function() {
var buttons = this.querySelectorAll('input[type="submit"]');
buttons.forEach(function(button) {
button.setAttribute('disabled', 'disabled');
});
}, false);
When using querySelectorAll
we need to iterate through the returned elements which is where forEach
comes in. If you are requiring support for older browsers you may need to use a regular for
loop.
Disable the Form Using a Class
If the value of your form’s submit button needs to be submitted with the rest of the form data disabling it will break things; in this case we need to track whether or not the form has been submitted. This was the case that my colleague was in. A simple way of doing this is by adding a class to the form on first submission and catching further attempts to submit the form when the class is present.
var form = document.querySelector('form');
form.addEventListener('submit', function(e) {
var submittedClass = 'js-submitted';
if (this.classList.contains(submittedClass)) {
e.preventDefault();
} else {
this.classList.add(submittedClass);
}
}, false);
Here we’ve used the class name js-submitted
to indicate whether or not the form has been submitted (I like to prefix classes used by JavaScript with js-
to scope them and keep them separate from those used for styling). The first time the form is submitted, i.e. the first time the submit button is clicked, the class is attached to the <form>
element; subsequent clicks will pick up on the class and prevent further submissions from taking place due to the event being suppressed by e.preventDefault()
.
Support for classList
is reasonably good, but it you need to support IE9 or lower it isn’t going to work. In which case we need to modify the code so that we can check for classList
support and add a fallback method if it isn’t available to us:-
var form = document.querySelector('form');
form.addEventListener('submit', function(e) {
var submittedClass = 'js-submitted';
if (
this.classList && this.classList.contains(submittedClass)
|| new RegExp('(^| )' + submittedClass + '( |$)', 'gi').test(this.className)
) {
e.preventDefault();
} else {
if (this.classList) {
this.classList.add(submittedClass);
} else {
this.className += ' ' + submittedClass;
}
}
}, false);
Final Words
So there you have two different approaches to preventing multiple clicks on a form’s submit button sending multiple requests. This can be particular useful when dealing with an e-commerce site where you want to make sure a user doesn’t end up making multiple requests to a payment gateway. It’s always worth remembering that not everyone is on a fast internet connection, and in the real world this can be a problem which disabling form submissions after the first event can resolve.
Personally I’d use the first option of disabling the submit buttons on a page as it provides obvious feedback to the user that the submit button can no longer be pressed. You could of course style the buttons once the form has the js-submitted
class attached, but I’m not a fan of the text value of a submit button being important to how a form gets processed; you never know when that text is going to need to change which would result in a need for the server-side logic changing too which increases the maintenance cost.
I hope these framework agnostic JavaScript solutions are of use.