It’s that thing I always forget, until users remind me.
While most of us (developers) know that double-clicking is not necessary on the web, there’s at least two people out there who don’t know. And about half of them are double-clicking your submit buttons (he said, knowing it was hyperbole).
It always comes to light well after I have deployed – mysterious timeout errors in the logs, “User not found” exceptions, and so on. Some weird behaviors can come from this if you’re not protecting your users from submitting things twice. I’ve been lucky enough to not have any catastrophic failures, but imagine if you were processing payments and didn’t have this kind of protection. That would be catastrophic.
There are a couple of solutions that come to mind:
The first solution that comes to mind: Disable Submit Buttons on click. Just a little bit of JavaScript can do this, and it provides some basic protection from double submits. My recommendation would be to disable the button, submit the form programmatically (XHR/Fetch request), then handle appropriately on response. This gives you the benefit of listening for errors in the response and displaying them without attempting to redirect the user (just don’t forget to event.preventDefault()
!)
The second solution, VERY similar to the first, would be to replace the submit button with a loading spinner or progress indicator. The implementation should be about the same, but it creates a different aesthetic. (I actually like this one better… I feel like the spinner or indicator is ‘positive’, whereas a disabled button denotes ‘negative’ – but that may be just me)
The third solution, assign a unique ID to the submission and handle it on the back-end. This one is not as trivial to implement, but it leaves it up to the back-end to accept or reject the request. It requires generating the unique ID and placing it on the page before it is served, and tracking pending IDs on the back-end. You would also need to handle the idea that not every form will be submitted – some users will bounce without using the form you worked so hard on. In that case, the ID would need to be discarded on the back-end to prevent stale IDs from being stored.
I have never actually implemented the third solution, but it sounds like a fun one to tackle, if only for the exercise.
What other solutions have you heard of for this issue? I’d love to hear about them below!