Search

Search components, tokens, patterns, architecture

Components

Loading States

Peri is local-first and renders instantly, so it has no skeletons. Loading UI exists only where real waits exist: Drive sync, wearable import, and PDF export. Don't fake latency.

The three real waits

Background Drive syncSyncing…

Importing wearable data

Night 14 of 30 · sleep stages

Generating PDF…
WaitSurfaceBlocking?
Google Drive syncsync dot pulse + caption in the top barNo — background, app fully usable
Wearable importSyncProgressModal with progress feedbackYes — data integrity during import
PDF export“Generating PDF” interstitial → “Export ready” sheet (file card, share/download, Done)Yes — short, with a completion artifact

The no-skeleton rule

Engines compute synchronously from local data — there is nothing to wait for on render. A skeleton would advertise latency the product doesn't have.

If a future surface gains real async

Inherit the rule: show progress only for the actual wait, name what is happening (“Night 14 of 30”), and keep the rest of the app readable. Blocking is reserved for data-integrity operations.

Do

  • ·Name the operation and its progress concretely
  • ·Keep background syncs in the status dot, out of the way
  • ·End blocking waits with a tangible artifact (the PDF card)

Don't

  • ·Add skeletons or shimmer to local-first surfaces
  • ·Show spinners without labels
  • ·Block the dashboard for background syncs

Accessibility

  • Progress modals announce updates via aria-live; the spinner alone is decorative.
  • Blocking modals trap focus and explain why they block.