KQ-1659 · OFFLINE/SHELF

Offline Shelf

A list that failed to load, shown honestly: a banner says the server cannot be reached and why, a countdown runs to the next automatic attempt, and under it sits what the device kept, each row wearing a Cached mark. The wait is one motion value running down at the rate of time; a failed attempt refills it to the next, longer delay on springs.glide. Back online, the marks lift off down the list on cascade() — a stamp rises, grows and turns as it fades on the exit ease — while the fresh rows slide in above on springs.glide, and losing the connection again presses the stamps back on with springs.recoil. R retries now from anywhere inside; the rows are one tab stop where the arrows move and Enter opens.

KQ-1659 · OFFLINE/SHELF

Inspections

Fieldline · 6 items saved on this device

Offline

We can't reach Fieldline.

The request timed out after 30 seconds. Showing what this device saved 2 h ago. ETIMEDOUT

Next try in 4 s

Up and Down move between rows, Enter opens one. R retries now.

offline · 6 saved on this device

Install

One command — the source lands in your repo. Or copy it from the Code tab.

$ pnpm dlx shadcn@latest add @kinetiq/offline-shelf

Props

cachedItems
OfflineShelfItem[]
default defaultOfflineShelfCached
What the device kept from the last load: { id, title, place?, kind?, updatedAt }.
freshItems
OfflineShelfItem[]
default the cached items, re-verified
What the server sent once it answered. New ids slide in above the cached rows; known ids take the fresh copy with a brief wash.
status
"offline" | "online"
default "offline"
Whether the server can be reached. Online lifts the marks and folds the banner away.
error
string | { message: string; code?: string }
default a 30-second timeout, ETIMEDOUT
Why the list did not load, shown as it is with its code in mono.
cachedAt
number
default two hours before now
When the cache was written, in ms; drives the stamps' age and the banner copy.
now
number
default defaultOfflineShelfNow
The moment ages count from, in ms; never read from the clock during render.
retryDelays
number[]
default [5, 10, 20, 40, 60]
Seconds to wait before each automatic attempt; the last one repeats.
onRetry
(cause: "auto" | "manual", attempt: number) => void | Promise<unknown>
default —
An attempt starts. Resolve once the server answered and set status to "online"; reject, or return nothing, and the next wait is longer.
onOpenCached
(item: OfflineShelfItem) => void
default —
A cached row was opened (Enter or a press) while offline.
onOpen
(item: OfflineShelfItem) => void
default —
A row was opened while online.
paused
boolean
default false
Hold the countdown where it is.
retryStyle
"ring" | "bar" | "ticks"
default "ring"
How the wait is drawn: a ring that drains round the seconds, a hairline bar along the banner, or ten ticks going out.
stampStyle
"stamp" | "tag" | "dim"
default "stamp"
How a cached row is marked: a rotated rubber stamp with a double rule, a quiet tag, or a dimmed row with a clock.
tone
"quiet" | "amber" | "cobalt"
default "quiet"
The banner's rule, icon, wash and wait colour.
title
string
default "Inspections"
The list's name; also the surface's accessible name.
source
string
default "Fieldline"
What cannot be reached, used in the copy and the announcements.
maxHeight
number
default 540
Tallest the surface grows before its list scrolls inside, px.
disabled
boolean
default false
Nothing can be retried or opened and the countdown holds; the surface dims.
className
string
default —
Classes for the outer surface.