Async Actions
Practical patterns for in-flight UI, double-submit prevention, and clear success or failure.
01 — Foundation
Async actions need visible state
Every server round-trip should answer: did it start, is it still running, and what happened?
Async actions — form submits, API calls, background updates — are where double clicks, duplicate charges, and lost focus cause the most damage. The UI must communicate state on the control that triggered the action.
02 — Controls
Buttons and forms during requests
Disable with purpose, label clearly, and restore on failure.
- disable the triggering control while the request is in flight — or the whole form when needed
- change label — “Submitting…”, “Processing payment…” — not a spinner alone
- prevent double submission — disable submit, debounce, or idempotent server handling
- restore controls and focus on error so users can fix and retry
<button type="submit" disabled aria-busy="true">
Saving…
</button> 03 — Feedback
Success, failure, and partial completion
Inline feedback beats mystery spinners that vanish without explanation.
- success — inline confirmation or status region; see Confirmation
- failure — specific message and recovery; see Error States
- long tasks — progress or step text; see Loading States
- optimistic UI only when rollback is safe and errors are obvious
04 — Accessibility
Keyboard and assistive technology
Busy state must be programmatic, not only visual grey-out.
-
aria-busy="true"on the relevant region while content updates - do not move focus unexpectedly when a request completes
- announce outcomes with live regions — sparingly, and in context
05 — Review
Before you approve
A short checklist for async actions in code review.
- in-flight state is visible; double submit is prevented
- success and failure are specific and recoverable
- offline and timeout cases are handled — see Offline States