E1.09.1submit lockoutdesignresearch

Lock the control immediately after submit to prevent a second send

Aliases: double submit · submit lock · in-flight disable

What it is

Once a request leaves, the button that fired it must immediately become unclickable—a submit lockout. The lock prevents one intent from being sent twice: two orders, two mails, two charges. It sits after the pressed state and before a result. A spinner is appearance; the lock is the mechanism.

Why it happens

Between the first sample and server confirmation there is a blank that feels like “nothing moved.” A second click in that blank is rational. If the button still takes pointer events, the second click becomes a second request. An idempotent API can swallow some duplicates; checkout, payment, and one-time codes usually cannot. The lock has to happen on the client frame that sends the request, not when HTTP returns: the slower the response, the wider the double-send window. Disabling the pointer is not enough; Enter, Space, and the form’s default submit still fire. The lock is a gate; loading appearance is a caption on the gate. A spinner with no gate is a busy performance that still accepts a second hit.

Studying it

Log request count against a submit API with tunable delay. Vary lock timing: on press, when the spinner appears, when the response arrives. Let people click freely in the blank.

Independent variables: lock timing, network delay, whether keyboard submit is locked too. Dependent variables: requests per intent, double-order rate, reports of “I clicked twice because nothing happened.”

A lab delay fixed at 300 ms often never sees a second click. Stretch delay to 1–3 seconds and allow real impatience to see the cost of an unlocked control.

Where it stops holding

Instant local actions (switching a tab) need no lock. Steppers and game fire that must repeat would be broken by a lock; throttle instead. After failure the control must unlock or it stays dead—that unlock is a different point. Optimistic UI that pretends success can desynchronize the lock from the spinner; do not watch the spinner alone.

Applying it

  • Set the button non-interactive in the same call that sends the request, then paint loading. Do not reverse that order.
  • Cut pointer, Enter, Space, and form submit together; a disabled look with live listeners is not a lock.
  • Still de-dupe on the server; the client lock is not the only line.
  • Verify on a 2-second delayed payment test: each intent must produce one request. A second request means the lock was late or missed a channel.

Related

  • Within the group: E1.09.2 Loading must keep the button’s size stable · E1.09.3 Long loads need a cancel
  • Adjacent: E1.17 Loading buttons and double-submit prevention · E1.02 Button states · I2 Loading and waiting
  • Search terms: double submit · submit lockout · idempotency

Cards in the same group

Quick Actions

Share

Share this page

ios_share

https://hci.top/en/handbook/E1.09.1