Back to compare picker

Retry vs Error state vs Loading spinner vs Offline state

Use retry when the product has a specific failed operation whose original scope can be preserved and safely attempted again.

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 Use retry when a specific operation likely failed for a transient reason and the same operation can be attempted again without losing user context or duplicating side effects.Help users recover when expected loading, saving, validation, sync, permission, or computation fails without losing their work.Use a loading spinner for short indeterminate waits where the system is actively working but cannot yet expose progress; resolve it quickly to content, success, cancellation, progress, or error.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.Reports could not load appears in the report section with the saved filter, Retry, Use cached data, and Contact support actions.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 A generic Try again button appears after every error, including validation and permission failures users cannot fix by repeating the request.Tiny transient toast for a blocking failure.A blank page shows a large spinner with no text, no affected object, and no idea what is loading.A blank page says You are offline even though the app has cached drafts and help content.
Good UX A user retries the same export after a network timeout, sees the attempt change to sending, and then returns to the recovered download state without re-entering filters.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.The app keeps a spinner on Save during airplane mode and never explains that no network request can start.
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.A short action, request, save, submit, refresh, sync, or fetch is actively processing and progress cannot be meaningfully measured.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.Idle state with no spinner and the action or region ready.Online normal state with no offline warning.
Accessibility burden Use an action label that names the operation, not only an icon or generic phrase.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
Use retry when a specific operation likely failed for a transient reason and the same operation can be attempted again without losing user context or duplicating side effects.
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
A generic Try again button appears after every error, including validation and permission failures users cannot fix by repeating the request.
Good UX
A user retries the same export after a network timeout, sees the attempt change to sending, and then returns to the recovered download state without re-entering filters.
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
Use an action label that names the operation, not only an icon or generic phrase.
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
Help users recover when expected loading, saving, validation, sync, permission, or computation fails without losing their work.
Good UI
Reports could not load appears in the report section with the saved filter, Retry, Use cached data, and Contact support actions.
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
Use a loading spinner for short indeterminate waits where the system is actively working but cannot yet expose progress; resolve it quickly to content, success, cancellation, progress, or error.
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 blank page shows a large spinner with no text, no affected object, and no idea what is loading.
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
A short action, request, save, submit, refresh, sync, or fetch is actively processing and progress cannot be meaningfully measured.
Avoid when
The content layout is predictable and a skeleton would better preserve structure.
Required state
Idle state with no spinner and the action or region ready.
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
The app keeps a spinner on Save during airplane mode and never explains that no network request can start.
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
Online normal state with no offline warning.
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.