Offline Sync Queue

(No Connection)

You are working with the door shut.

The network stopped answering, so nothing is leaving this device. Keep going anyway. Everything held below sends itself the moment the line comes back.

Trying again in 20 seconds. Attempt 1.

Held on this device

Listening for the network
  • Draft: Harbour case studyEdited 4 minutes agoQueued
  • Comment on the Meridian briefWritten 9 minutes agoQueued
  • Two uploaded imagesAdded 12 minutes agoWaiting for upload

Closing the tab is safe. The queue survives until it clears.

About this block

Offline Sync QueuePRO

Offline screen built around a live sync queue: a display headline with a retry pill and a self-restarting countdown that raises the attempt number, beside a soft panel listing every change held on the device with a pulsing listening indicator.

Error31: Offline Sync Queue

An offline screen built around what is still waiting to send: the statement and a retry pill sit beside a soft panel listing every change held on the device, with a countdown that restarts itself and raises the attempt number each time it lapses.

Upgrade to Pro

Pro blocks install through the shadcn CLI with your license key and ship their full source. Docs and live previews stay open to everyone, so you can read every block's details first.

Upgrade Now

Installation

Swap YOUR_EMAIL and YOUR_KEY for the email and license key on your account. Find your license key on your account page.

Radix flavor

bash
npx shadcn add "https://ui.beste.co/r/error31?email=YOUR_EMAIL&license_key=YOUR_KEY"

Base UI flavor

bash
npx shadcn add "https://ui.beste.co/r-base/error31?email=YOUR_EMAIL&license_key=YOUR_KEY"

This installs the block to components/beste/block/error31.tsx, plus the two design-system primitives it renders through: badge7 for the parenthetical eyebrow and button12 for the retry pill.

Quick start

The installed file exports error31Demo alongside the block: the exact props behind the preview above. Spread it and the retry loop starts immediately.

tsx
import { Error31, error31Demo } from "@/components/beste/block/error31";

export default function Offline() {
  return <Error31 {...error31Demo} />;
}

Feed the queue from your own outbox and let the loop drive the reconnect attempt:

tsx
"use client";

import { Error31 } from "@/components/beste/block/error31";

export default function Offline({ pending }: { pending: { title: string; meta: string }[] }) {
  return (
    <Error31
      badge={{ label: "No Connection" }}
      heading="You are working <strong>with the door shut</strong>."
      description="The network stopped answering, so nothing is leaving this device."
      labels={{
        retry: "Knock again",
        countdown: "Trying again in",
        seconds: "seconds",
        attempt: "Attempt",
        queueTitle: "Held on this device",
        queueStatus: "Listening for the network",
        note: "Closing the tab is safe. The queue survives until it clears.",
      }}
      retrySeconds={20}
      queue={pending.map((item) => ({ ...item, state: "Queued" }))}
      onRetry={() => flushOutbox()}
    />
  );
}

Props

PropTypeDefaultDescription
badge{ label: string }–Parenthetical eyebrow above the headline
headingstring–Headline HTML, rendered as an h1; <strong> marks the muted clause
descriptionstring–Explanatory paragraph under the headline
labelsError31Labels{}Retry text, countdown sentence, unit word, attempt word, and the panel captions
retrySecondsnumber–Interval of the automatic retry loop
queueQueueItem[][]Changes held on the device
onRetry() => void–Called on every automatic lapse and on every manual press
classNamestring–Extra classes for the outer <section>
ts
type Error31Labels = {
  retry?: string;
  countdown?: string;
  seconds?: string;
  attempt?: string;
  queueTitle?: string;
  queueStatus?: string;
  note?: string;
};

type QueueItem = {
  title: string;
  meta?: string;
  state: string;
};

Behavior notes

  • The countdown loops rather than ending: each time it reaches zero it calls onRetry, resets itself to retrySeconds and increments the attempt number, so the page keeps probing for a connection on its own.
  • Pressing the retry pill runs the same path immediately: it resets the countdown, raises the attempt number and calls onRetry, so a manual press and an automatic lapse are indistinguishable to the handler.
  • Passing no retrySeconds (or 0) disables the loop entirely. The countdown line disappears and the pill becomes a plain manual retry.
  • The status indicator beside the panel title is a dot on Tailwind's animate-pulse utility, a plain CSS animation with no JavaScript behind it and no custom keyframe to install.
  • The countdown line is marked aria-live="polite", so screen readers hear the remaining time and the attempt number without the page grabbing focus.
  • The panel, including its indicator and note, only renders when queue is non-empty, which turns the block into a plain offline statement when nothing is pending.

More Error blocks

View all Error
FREE

error35

Server Error With Live Status

PRO

error17

Maintenance Window Notice

PRO

error22

Planned Downtime Window

Get Pro access