Speed Patterns octocat github link burger menu

Acknowledge Actions

By Sergey Chernyshev · · Assisted by AI

When a user clicks a button, taps a link, or submits a form, they expect immediate feedback. If the system takes longer than about 100ms to respond, an unacknowledged action becomes a usability problem — and a performance problem.

The Problem

Without acknowledgment, the user is left to guess:

This isn't a hypothetical — duplicate form submissions are a classic symptom of missing acknowledgment, and most engineers have seen the resulting "duplicate order" tickets. The same frustration shows up as rage clicks — repeated, accelerating taps on the same element that real-user monitoring tools flag as a user-frustration signal. A button that gives no feedback for a couple of seconds is the most reliable way to manufacture them.

The threshold matters: research on perceived responsiveness consistently puts roughly 100ms as the upper bound for an action to feel instantaneous. Any longer, and the user notices the delay. Beyond about a second, the user starts to disengage entirely.

Solution

The same control on click: idle state on the left, immediately disabled with a "Submitting…" label and inline indicator on the right.

Two buttons: a yellow 'Submit' button labeled 'idle button', and a dashed-border orange 'Submitting…' button with a small rotating indicator labeled 'acknowledged + disabled'
Acknowledge every click

Give the user visible feedback the instant their action begins, separate from the action's actual completion. The acknowledgment is a UI-only concern — it doesn't have to wait for the network.

Common acknowledgments

Guidelines

Why This Works

The technical work behind the action hasn't gotten any faster, but the experience has. The user knows the system is working on their behalf, can see exactly which action is in progress, and isn't tempted to retry. The site feels responsive even when the network isn't.

Related Patterns

Technical Implementation

A minimal form submission acknowledgment is essentially two lines of code: disable the button and change its label as soon as the submit event fires.

<button type="submit" id="submit-btn">Submit</button>
form.addEventListener("submit", () => {
  const btn = document.getElementById("submit-btn");
  btn.disabled = true;
  btn.textContent = "Submitting…";
});

This costs almost nothing to implement, and it makes the slow path feel intentional rather than broken. The same pattern applies to any control that initiates work — change the visual state in the same frame as the input event, not after the response returns.