Offline UX

Offline UX is not a banner that says “offline.” It is the product contract for what is saved, what is pending, what failed, and what the user can do next.

Required States

StateUser copyApp behavior
saved locally”Saved on this device”no network required
pending sync”Saved locally, waiting to sync”keep mutation in durable queue
failed sync”Saved locally, sync failed”show retry and reason
conflict”Needs your choice”preserve both versions
storage pressure”Storage is almost full”offer export, cleanup, and retry
stale data”Last updated 3 days ago”show last successful sync/fetch

UX Rules

  1. Confirm local save before network save.
  2. Show pending state near the affected object, not only in a global status icon.
  3. Let users retry failed sync without duplicating actions.
  4. Keep destructive restore/import behind a dry-run or confirmation.
  5. Make export obvious before users need it.
  6. Explain degraded mode in product language.

Queue Status Example

type SyncStatus =
  | { state: "local-only" }
  | { state: "pending"; count: number }
  | { state: "syncing"; count: number }
  | { state: "failed"; count: number; lastError: string }
  | { state: "conflict"; count: number };

Trust Copy

Use exact words:

  • “Your data stays on this device.”
  • “Export CSV anytime.”
  • “Backup is encrypted before it leaves this device.”
  • “Sync failed, but your local changes are safe.”

Avoid vague words:

  • “seamless”
  • “cloud-safe”
  • “automatically protected”
  • “never lose data” unless restore gates prove it