jQuery & JavaScript

Disable the submit button after the form is submitted (jQuery and ASP.NET)

jQuery & JavaScript · · Published 2026-09-21

Users double-click buttons, especially when a page is slow. On a payment or order form that means two orders. Disabling the button once the form is on its way prevents most duplicates, but on a Web Forms page there are two traps: a disabled submit button is not posted, so its Click event never fires, and validation may have stopped the submit anyway.

The trap

// Looks right, breaks the server event:
$("#<%= btnOrder.ClientID %>").on("click", function () {
  $(this).prop("disabled", true);
});

ASP.NET knows which button was clicked because the browser posts the button's name and value. A button disabled before the form is submitted is not included, so btnOrder_Click silently does nothing.

Solution 1: UseSubmitBehavior="false" (Web Forms)

<asp:Button ID="btnOrder" runat="server" Text="Place order" OnClick="btnOrder_Click"
    UseSubmitBehavior="false"
    OnClientClick="if (typeof Page_ClientValidate === 'function' && !Page_ClientValidate()) return false; this.disabled = true; this.value = 'Sending…';" />

With UseSubmitBehavior="false", ASP.NET renders a plain button that posts through __doPostBack, which sends the button's identity in the __EVENTTARGET field. Disabling the button no longer loses the event. The script first runs client validation (if validators are on the page) so the button is not disabled for a form that will not be sent.

Solution 2: disable on the form's submit event (jQuery)

$(function () {
  $("form").on("submit", function () {
    var $form = $(this);
    // let validation cancel the submit first
    if (typeof Page_IsValid !== "undefined" && !Page_IsValid) return;
    // defer so the clicked button's name/value is captured before disabling
    setTimeout(function () {
      $form.find("input[type=submit], button[type=submit]")
           .prop("disabled", true)
           .addClass("is-busy");
    }, 0);
  });
});

The form's submission data is constructed when the submit happens, so disabling the buttons in a zero-delay timeout leaves the clicked button's value in the request. This works for plain HTML forms too. If a validator fails, Web Forms' own script cancels the submit before this handler matters.

With an UpdatePanel, the page is not reloaded after an asynchronous postback, so re-enable the buttons in a Sys.WebForms.PageRequestManager endRequest handler.

The server must still check

Script can be off, a request can be replayed, and two tabs can submit the same order. Make the operation idempotent on the server: generate a unique token when the form is shown (in a hidden field), store it with the order, and reject a second order with the same token, for example with a unique index.

protected void Page_Load(object sender, EventArgs e)
{
    if (!IsPostBack) hfOrderToken.Value = Guid.NewGuid().ToString("N");
}

protected void btnOrder_Click(object sender, EventArgs e)
{
    if (!Guid.TryParseExact(hfOrderToken.Value, "N", out Guid token)) return;
    bool created = OrderService.TryCreate(token, ReadOrderFromForm()); // unique index on token
    lblResult.Text = created ? "Order placed." : "This order was already received.";
}

A related helper is enabling and disabling a TextBox from a button.

Official documentation