Background Sync Status Panel — Free Queue-and-Retry UI Pattern

Background Sync Status Panel · Dashboards · Plain HTML, CSS & JS · Live preview

Share & Support

What's included

Features

Real online/offline detection
navigator.onLine and window events genuinely drive state.
Honest simulated sync engine
Queue processing simulated, clearly labeled as such.
Real API shown as a comment
registration.sync.register() usage documented, not executed.
Three-way support detection
Full support, SW-only, and no-SW states each explained.
Visible state machine
queued → syncing → synced with distinct badges.
Manual offline toggle
Test the flow without physically disconnecting.
Auto-retry on reconnect
Queue flushes automatically when connectivity returns.
No dependencies
Pure vanilla JS against native browser events.

About this UI Snippet

Background Sync Status Panel — Real Connectivity Signals, Simulated Sync Execution

Screenshot of the Background Sync Status Panel snippet rendered live

The Background Sync API lets a service worker retry a failed or offline action once connectivity genuinely returns — even if the tab that queued it has since closed. This snippet builds the queue/retry *state machine* for real, driven by real navigator.onLine and online/offline events, while being explicit that the actual sync-registration half is simulated rather than pretending a service worker registered successfully.

Why this can't run the real API end-to-end

A production Background Sync flow needs navigator.serviceWorker.ready to resolve, then registration.sync.register('tag') to queue a sync, then a service worker's own sync event handler to execute the retry — potentially minutes later, with no tab open at all. Service worker registration depends on a stable origin and scope; inside a sandboxed preview <iframe> (unpredictable origin, restrictive sandbox attributes, or a Permissions-Policy that blocks it), registration frequently fails inconsistently across environments. Rather than attempt a registration that might silently fail depending on exactly how the snippet is embedded, this demo simulates the queue-and-retry state machine directly — and shows the real registration.sync.register() call as a source comment, never executed.

Real signals driving a simulated engine

navigator.onLine and the window 'online'/'offline' events are universally supported and genuinely reflect the device's actual network state — nothing about those is faked. This snippet wires the queue's queued → syncing → synced state machine directly to those real events, plus a manual "simulate offline" toggle for testing the flow without physically disconnecting.

Feature detection, three-way

The support check distinguishes three real states: full Background Sync support ('sync' in ServiceWorkerRegistration.prototype), service workers available but the sync extension missing (true in Firefox and Safari, which have never implemented Background Sync), and no service worker support at all. Each gets distinct, accurate copy — none of them claim the simulated queue is doing real background execution.

A pattern worth the honesty

The queued-action-with-visible-retry pattern is genuinely useful UI regardless of whether the underlying sync is real or simulated — pair this with an uptime status page or status dashboard for a fuller connectivity-aware operations view.

Build with AI

Build, Understand, Optimize, and Extend It With AI

Paste this snippet's HTML, CSS, and JS into an AI coding assistant like Claude and ask it to explain why a real Background Sync implementation needs a service worker's own 'sync' event handler (registered via registration.sync.register()) rather than page-level JavaScript, and why that execution can happen even after the tab that queued the action has closed — which is precisely what this demo's setTimeout-based simulation can't replicate, since it only runs while the page is open. It's also useful for reasoning about sandboxed-preview constraints more broadly — ask why service worker registration is unreliable inside iframes and what specific conditions (origin stability, sandbox attributes, Permissions-Policy) affect it. For extensions, ask it to sketch the actual service worker file this pattern would need in production, including a minimal sync event handler and an IndexedDB-backed queue for real persistence across page reloads. Treat the code less like a finished artifact and more like a starting point for a conversation.

Prompt to recreate it

Copy this into your AI assistant of choice to build the effect from scratch, or as a jumping-off point for your own variant:

text
Build a "background sync status panel" in plain HTML, CSS, and JavaScript demonstrating the queue-and-retry UX pattern behind the Background Sync API — no actual service worker registration, no libraries.

Requirements:
- A connection indicator (dot + label) reflecting real navigator.onLine state, updated live via the window 'online' and 'offline' events, plus a manual "simulate offline / simulate online" toggle button for testing without physically disconnecting.
- A text input plus "Queue action" button that adds items to a visible queue list, each item showing one of three states with a distinct badge: queued, syncing, synced.
- CRITICAL: implement the actual sync EXECUTION (the transition from queued to syncing to synced) as an honestly-labeled SIMULATION using setTimeout, NOT a real navigator.serviceWorker / SyncManager registration — because a real service worker frequently fails to register inside a sandboxed preview iframe (unstable origin/scope, restrictive sandbox attributes, or Permissions-Policy restrictions), attempting the real API here would produce inconsistent, confusing behavior depending on the embedding context. Queued items should only begin "syncing" once the connection is (really or simulatedly) online, and should auto-flush automatically when the online event fires or the manual toggle switches back to online.
- Include the REAL production code as a code comment (not executed) showing navigator.serviceWorker.ready.then(registration => registration.sync.register('tag-name')) for queuing a sync, and a self.addEventListener('sync', ...) handler example for what the service worker file itself would contain to process it — clearly marked as illustrative, unexecuted reference code.
- Feature-detect Background Sync support with something like `window.ServiceWorkerRegistration && 'sync' in ServiceWorkerRegistration.prototype` and also check `'serviceWorker' in navigator` separately, showing three distinct, accurately-worded status states: full Background Sync support, service-worker-but-no-sync support (true in Firefox/Safari), and no service worker support at all — in every case, the visible queue/retry UI must still work identically via the simulation.
- UI copy and code comments must be explicit and unambiguous that the actual background execution shown is a simulation using real connectivity signals (navigator.onLine, online/offline events) but simulated sync processing — never implying a real service worker registered or that sync would survive the tab actually closing.

Want to tighten it up first? Run this prompt through the AI Prompt Studio to score it across 8 quality dimensions, catch anti-patterns, and tune the wording for Claude, ChatGPT, or Gemini before you paste it in.

Step by step

How to Use

  1. 1
    Paste HTML, CSS, and JSA connection indicator and empty sync queue render.
  2. 2
    Type an action and queue itWhile online, it syncs immediately through the simulated engine.
  3. 3
    Click "Simulate going offline"New actions now queue instead of syncing.
  4. 4
    Queue a few actions offlineThey sit in "queued" state.
  5. 5
    Click "Simulate coming back online"Queued actions transition queued → syncing → synced.
  6. 6
    Read the noteExplains exactly which parts are real versus simulated.

Real-world uses

Common Use Cases

Offline-first forms
Queue submissions made while disconnected.
Draft-saving apps
Retry saves automatically once back online.
Ops/connectivity dashboards
Pair with a status dashboard.
PWA reliability demos
Illustrate the queue-and-retry pattern to stakeholders.
Field-service apps
Show pending actions while working in low-connectivity areas.
Uptime-adjacent tooling
Alongside an uptime status page.

Got questions?

Frequently Asked Questions

Partially, and it says so explicitly. The connectivity detection (navigator.onLine, the online/offline window events) is completely real and works identically everywhere. The actual sync EXECUTION — a service worker retrying a queued action once connectivity returns — is simulated with a setTimeout-driven state machine, because service worker registration frequently fails inside a sandboxed preview iframe. The real registration.sync.register() call this would use in production is included as a source comment.

Service worker registration depends on a stable origin and scope, and many sandboxed preview/iframe environments either can't provide one consistently, restrict it via the iframe's sandbox attribute (missing allow-same-origin), or block it via Permissions-Policy. Rather than attempt a registration that might succeed in one embedding context and silently fail in another — producing inconsistent behavior depending on exactly how the snippet is viewed — this demo simulates the queue engine directly using signals that work everywhere.

It mirrors what a real Background Sync flow does: an action is queued while offline (or immediately attempted if online), transitions to syncing once connectivity is available and the service worker's sync event fires, then to synced once the retry succeeds. This demo drives the same three states from real online/offline detection, just executing the "syncing" step with a timer instead of an actual network request from a service worker.

No — it's a Chromium-only extension to the Service Worker API (Chrome, Edge, Opera, Android WebView, Samsung Internet). Firefox and Safari, including iOS Safari, have never implemented it, so 'sync' in ServiceWorkerRegistration.prototype is false there even though service workers themselves are supported. This snippet's feature-detection distinguishes that case from full support and from no service worker support at all, with distinct explanatory copy for each.

Register a service worker, call navigator.serviceWorker.ready.then(reg => reg.sync.register('tag-name')) when an action needs to be queued, and add a self.addEventListener('sync', event => { if (event.tag === 'tag-name') event.waitUntil(retryQueuedActions()) }) handler inside the service worker file itself — the browser then invokes that handler automatically once connectivity returns, even without any tab open. You'd also want a fallback (like this snippet's simulation) for browsers lacking Background Sync support.