How to Disable HTML Element on Click

Very simple way to disable a UI element such as a submit button when it's clicked using JavaScript with ~20 lines of code.

"Is this thing working?!?!"

A common UX issue I see with web apps is that when a button is clicked then it should be disabled until the action it performs is completed. When working with AJAX websites I see people forget about this all the time which means the user has no idea if the site is actually working so they just click on the button over and over and over. This is rarely the site developer wanted and can often cause weird things to happen or create multiple records and not to mention just down right frustrating for the user. Long story short this is just a bad user experience and should be handled.

Some people solve this by adding an obnoxious "Loading..." overlay for the entire page or form but that's a bit much don't you think? There are even many plugins out there that claim to handle this by doing similar things. Why add a big plugin for something that is actually really easy to handle? What I've used for several years is a simple CSS and JavaScript approach that works for all browsers and is only about 20 lines of JavaScript (unminified). This approach doesn't require CSS file additions and when you need to disable or enable an element you just make a call to the JS functions that you can tuck away in your site's common JavaScript file.

Show me the code!!!

Here's the JavaScript code to add to your site's JS file.

function disableElement(element) {
    if ($("style#disabledElementStyles").length == 0) {
        $("").appendTo("head");
    }
    element.addClass("disabledElement");
    element.data("disabledEvents", element.data("events"));
    element.data("events", null);
};

function enableElement(element) {
    if (element.hasClass("disabledElement")) {
        element.removeClass("disabledElement");
        element.data("events", element.data("disabledEvents"));
        element.data("disabledEvents", null);
    }
};

function disableElements(elementArray) {
    elementArray.forEach(disableElement);
};

function enableElements(elementArray) {
    elementArray.forEach(enableElement);
};

How do you use it?

Using the code is very simple. At the beginning of some event that's triggered by an element you call the disableElement function. When your code is done and you want to let the user click the element again you call enableElement. If you have multiple elements you want to enable / disable there are functions that take an array of elements to enable or disable.

Here's a sample using a form submit event where we disable the submit button when the form is submitted.
$("#someForm").submit(function (e) {
    disableElement($("#submitFormButton"));
    //
    // Do some code such as an AJAX call.
    //
    enableElement($("#submitFormButton"));
});
That's it! One thing to keep in mind especially when doing AJAX calls is that if the call fails you should make sure you re-enable the button. A good way to do this if you're using jQuery is to use the .always() method of the AJAX call like this.
$("#someButton").click(function () {
    $.post("/someurl", data, function (data, status) {
        if (status == "success") {
            // Do whatever you need to do on success
        }
    }).fail(function (xhr, error) {
        // Handle the failure gracefully by showing error messages to the user
    }).always(function (data) {
        enableElement($("#someButton"));
    });
});

How does it work?

So what's going on here? If you can't figure it out from reading the code (which if you can't you should seriously just stop developing websites because this isn't hard stuff... or you're just learning so that's OK) all that's happening here is we're adding some CSS to the page, adding a CSS class to the element, and removing any events that are tied to the element by storing them in the data collection for the element so we can reapply them when we enable the element. That's it.

Try it out and if you see any issues feel free to let me know on Twitter @KFinley.