Back to compare picker

Retry vs Error state vs Loading spinner vs Offline state

Retry is the action contract for safely attempting the same failed operation again. Error state owns the persistent failure surface, loading spinner represents active pending work before success or failure is known, and offline state explains connectivity mode plus local or queued work.

Learn the decision

Match the interaction to the person's task

Retry is the action contract for safely attempting the same failed operation again. Error state owns the persistent failure surface, loading spinner represents active pending work before success or failure is known, and offline state explains connectivity mode plus local or queued work.

Retry

Use it when: A load, save, submit, upload, export, sync, payment, or background request failed for a transient or uncertain reason.

Make this state clear: Retryable failed state with affected operation, object, and preserved request context.

Observe the result: A second failure increases the wait before the next attempt and then offers cached export, background notification, or support reference after attempts are exhausted.

Study the full pattern →

Error state

Use it when: A system or task failure blocks expected content or action.

Make this state clear: Normal expected state before failure.

Observe the result: User input and filter context are preserved after failure, and retry returns to recovered content or a clear still-failed state.

Study the full pattern →

Loading spinner

Use it when: The operation has defined resolution, timeout, cancellation, or failure paths.

Make this state clear: Inline processing state for a button or small local action.

Observe the result: After submit, users see payment PAY-2048 processing, can tell the button is temporarily unavailable, and then get either success or retry guidance.

Study the full pattern →

Offline state

Use it when: Connection loss or server reachability changes the user's current task.

Make this state clear: Offline banner or local status that names affected scope.

Observe the result: A user loses connection while editing an inspection note, sees it saved on this device, attaches photos to a queue, and later watches the queue sync after reconnect.

Study the full pattern →

Practice the judgment: Imagine this situation: A generic Try again button appears for every failure and traps users in repeated validation or permission errors. Write the person's goal, choose one of these patterns, and show the state that helps the person continue. Use the decision rules and source trail below to explain your choice.

Review the underlying principle →

Decision dimensions

Dimension RetryError stateLoading spinnerOffline state
UI or UX UI + UX - Scoped failed-operation retry controlUI + UX - Recoverable failure surfaceUI + UX - Bounded indeterminate wait indicator for a named action or regionUI + UX - Connectivity-mode and local-work continuity state
UI guidance Place Retry next to the failed operation, object, or request summary, and name the exact action being retried such as Retry export or Retry payment authorization.Render a persistent error region near the affected content with a specific failure heading, plain-language cause, preserved context, and recovery actions.Render a compact spinner only beside, inside, or over the affected action, component, or page region, and pair it with concise text that names what is loading or processing.Show offline status where it changes the current task, naming what remains available such as cached reports, local draft editing, queued saves, or read-only history.
UX guidance Help the person reach a clear task outcome.Match the next action to the failure cause: retry transient failures, edit correctable input, use cached fallback for read-only continuity, or provide support reference when recovery is outside the UI.Prevent duplicate or conflicting actions while the operation is in flight, but keep context, status, safe cancellation, and timeout recovery available when the wait exceeds the expected threshold.Use offline state to preserve trust and task continuity when connection loss changes what users can read, edit, submit, sync, refresh, or share.
Good UI A report export card says Export CSV failed, keeps the saved filters visible, shows Attempt 1 of 3, and offers Retry export with request EXP-2048.A failed save state keeps the draft visible and labels the support reference separately from the user-facing explanation.A Pay invoice button becomes Processing payment with a small spinner, disables only duplicate payment actions, and leaves the invoice reference visible.A field report says Offline: 3 edits saved on this device, cached customer history shown from 10:42, Submit disabled until connection returns, and Retry connection.
Bad UI Retry creates duplicate records, payments, invitations, exports, or queued jobs.Tiny transient toast for a blocking failure.A search results panel shows skeleton rows, a spinner, and a progress bar for the same request.A blank page says You are offline even though the app has cached drafts and help content.
Good UX A second failure increases the wait before the next attempt and then offers cached export, background notification, or support reference after attempts are exhausted.User input and filter context are preserved after failure, and retry returns to recovered content or a clear still-failed state.After submit, users see payment PAY-2048 processing, can tell the button is temporarily unavailable, and then get either success or retry guidance.A user loses connection while editing an inspection note, sees it saved on this device, attaches photos to a queue, and later watches the queue sync after reconnect.
Bad UX The app retries aggressively every second during an outage and makes the service harder to recover.Clearing work after save failure.The spinner blocks the whole workspace for a small table refresh and prevents users from continuing other work.A submitted offline form disappears from the screen even though it was neither queued nor accepted by the server.
Best fit A load, save, submit, upload, export, sync, payment, or background request failed for a transient or uncertain reason.A system or task failure blocks expected content or action.The operation has defined resolution, timeout, cancellation, or failure paths.Connection loss or server reachability changes the user's current task.
Avoid when The error is caused by invalid user input and correction is required.Nothing exists yet and the state is expected.The content layout is predictable and a skeleton would better preserve structure.A single request failed while the rest of the app is reachable and an error state is clearer.
Required state Retryable failed state with affected operation, object, and preserved request context.Normal expected state before failure.Inline processing state for a button or small local action.Offline banner or local status that names affected scope.
Accessibility burden Expose pending, failed again, cooldown, succeeded, exhausted, and non-retryable outcomes through status text or live regions.Use appropriate alert or status semantics for newly appearing critical errors.Give the spinner or affected region an accessible name that identifies the operation.Announce significant connectivity changes with status messaging when they affect the current task.
Common misuse Offering Retry for every error regardless of whether the user or system state can change.Using a transient toast for critical errors.Showing an unlabeled spinner on a blank page.Showing only a browser-style offline page when useful cached or local content exists.

Retry

UI or UX
UI + UX - Scoped failed-operation retry control
UI guidance
Place Retry next to the failed operation, object, or request summary, and name the exact action being retried such as Retry export or Retry payment authorization.
UX guidance
Help the person reach a clear task outcome.
Good UI
A report export card says Export CSV failed, keeps the saved filters visible, shows Attempt 1 of 3, and offers Retry export with request EXP-2048.
Bad UI
Retry creates duplicate records, payments, invitations, exports, or queued jobs.
Good UX
A second failure increases the wait before the next attempt and then offers cached export, background notification, or support reference after attempts are exhausted.
Bad UX
The app retries aggressively every second during an outage and makes the service harder to recover.
Best fit
A load, save, submit, upload, export, sync, payment, or background request failed for a transient or uncertain reason.
Avoid when
The error is caused by invalid user input and correction is required.
Required state
Retryable failed state with affected operation, object, and preserved request context.
Accessibility burden
Expose pending, failed again, cooldown, succeeded, exhausted, and non-retryable outcomes through status text or live regions.
Common misuse
Offering Retry for every error regardless of whether the user or system state can change.

Error state

UI or UX
UI + UX - Recoverable failure surface
UI guidance
Render a persistent error region near the affected content with a specific failure heading, plain-language cause, preserved context, and recovery actions.
UX guidance
Match the next action to the failure cause: retry transient failures, edit correctable input, use cached fallback for read-only continuity, or provide support reference when recovery is outside the UI.
Good UI
A failed save state keeps the draft visible and labels the support reference separately from the user-facing explanation.
Bad UI
Tiny transient toast for a blocking failure.
Good UX
User input and filter context are preserved after failure, and retry returns to recovered content or a clear still-failed state.
Bad UX
Clearing work after save failure.
Best fit
A system or task failure blocks expected content or action.
Avoid when
Nothing exists yet and the state is expected.
Required state
Normal expected state before failure.
Accessibility burden
Use appropriate alert or status semantics for newly appearing critical errors.
Common misuse
Using a transient toast for critical errors.

Loading spinner

UI or UX
UI + UX - Bounded indeterminate wait indicator for a named action or region
UI guidance
Render a compact spinner only beside, inside, or over the affected action, component, or page region, and pair it with concise text that names what is loading or processing.
UX guidance
Prevent duplicate or conflicting actions while the operation is in flight, but keep context, status, safe cancellation, and timeout recovery available when the wait exceeds the expected threshold.
Good UI
A Pay invoice button becomes Processing payment with a small spinner, disables only duplicate payment actions, and leaves the invoice reference visible.
Bad UI
A search results panel shows skeleton rows, a spinner, and a progress bar for the same request.
Good UX
After submit, users see payment PAY-2048 processing, can tell the button is temporarily unavailable, and then get either success or retry guidance.
Bad UX
The spinner blocks the whole workspace for a small table refresh and prevents users from continuing other work.
Best fit
The operation has defined resolution, timeout, cancellation, or failure paths.
Avoid when
The content layout is predictable and a skeleton would better preserve structure.
Required state
Inline processing state for a button or small local action.
Accessibility burden
Give the spinner or affected region an accessible name that identifies the operation.
Common misuse
Showing an unlabeled spinner on a blank page.

Offline state

UI or UX
UI + UX - Connectivity-mode and local-work continuity state
UI guidance
Show offline status where it changes the current task, naming what remains available such as cached reports, local draft editing, queued saves, or read-only history.
UX guidance
Use offline state to preserve trust and task continuity when connection loss changes what users can read, edit, submit, sync, refresh, or share.
Good UI
A field report says Offline: 3 edits saved on this device, cached customer history shown from 10:42, Submit disabled until connection returns, and Retry connection.
Bad UI
A blank page says You are offline even though the app has cached drafts and help content.
Good UX
A user loses connection while editing an inspection note, sees it saved on this device, attaches photos to a queue, and later watches the queue sync after reconnect.
Bad UX
A submitted offline form disappears from the screen even though it was neither queued nor accepted by the server.
Best fit
Connection loss or server reachability changes the user's current task.
Avoid when
A single request failed while the rest of the app is reachable and an error state is clearer.
Required state
Offline banner or local status that names affected scope.
Accessibility burden
Announce significant connectivity changes with status messaging when they affect the current task.
Common misuse
Showing only a browser-style offline page when useful cached or local content exists.
Decision rules
  • Use retry when the product has a specific failed operation whose original scope can be preserved and safely attempted again.
  • Use error state when expected content, save, sync, permission, validation, or computation has failed and users need a persistent explanation plus recovery choices.
  • Use loading spinner while a named action or region is actively pending and the system has not yet resolved success, failure, timeout, or cancellation.
  • Use offline state when the governing condition is connection loss, cached data, local-only work, queued actions, reconnect checks, or sync handoff.
  • Retry can appear inside an error state, but it should name the failed operation, preserve the same request context, and stop when the failure becomes non-retryable.
  • A spinner can transition into retry after timeout or failure, but retry should remove busy state and show attempt count, cooldown, and outcome.
  • Offline state may offer Retry connection or Retry sync, but it must still explain which work is local, stale, queued, or unavailable while disconnected.
  • Do not use retry for validation, permission, policy, final deletion, or unsupported-state failures; route users to edit, access request, explanation, or support.
  • For side-effecting operations, choose retry only when idempotency or deduplication prevents duplicate records, charges, messages, exports, or queue jobs.
  • For repeated failures, prefer capped backoff, retry limits, fallback, background completion, cached data, or support over aggressive immediate loops.
Inspect live examples
Failure modes
  • A generic Try again button appears for every failure and traps users in repeated validation or permission errors.
  • Retry clears the original form, filters, file selection, amount, or destination, causing users to repeat the wrong operation.
  • Retry and the original Submit button are both enabled while the same request is already in flight.
  • Automatic retries amplify service overload because no cap, cooldown, jitter, or server timing is respected.
  • A spinner remains visible after failure, so users cannot tell whether retry is available or already running.
  • Offline and service failure are collapsed into one retry button that hides cached, local, queued, or stale-data behavior.

Saved items