WebberUI

Suspense Reveal Queue

A reveal conductor wrapping several loading sections — whichever finishes first joins the queue, reveals follow the author's order with a minimum interval, and late sections catch up automatically.

This is a WebberUI Pro component

Free during the launch campaign: sign up or sign in, then hit “Copy install command” in the preview above and it installs straight away — no payment, no credit card. The command below returns 401 while you are signed out.

How to install Pro components →See the plans →

Loading preview…
npx shadcn@latest add "https://webberui.com/r/suspense-reveal-queue.json?t=<install token>"

Playground

Tune the props live — the code snippet updates as you go, so you can dial in the look you want before copying it.

200
<SuspenseRevealQueue />

Installation

npx shadcn@latest add "https://webberui.com/r/suspense-reveal-queue.json?t=<install token>"

Or, once registries are configured in components.json, install it as @webberui/suspense-reveal-queue.

Usage

SuspenseRevealQueue is the conductor, and you put several RevealSlot elements inside it. A slot does not pop in the moment it is ready — it joins the queue, and the conductor schedules every reveal centrally according to order and interval.

Controlled readiness (with your own loading state)

import {
  RevealSlot,
  SuspenseRevealQueue,
} from "@/components/ui/suspense-reveal-queue";

<SuspenseRevealQueue interval={200}>
  <RevealSlot order={0} ready={!profile.loading} fallback={<ProfileSkeleton />}>
    <Profile data={profile.data} />
  </RevealSlot>
  <RevealSlot order={1} ready={!chart.loading} fallback={<ChartSkeleton />}>
    <Chart data={chart.data} />
  </RevealSlot>
  <RevealSlot order={2} ready={!feed.loading} fallback={<FeedSkeleton />}>
    <Feed data={feed.data} />
  </RevealSlot>
</SuspenseRevealQueue>

Automatic mode (wrapping a Suspense boundary)

When ready is omitted, RevealSlot wraps its children in React.Suspense on its own and counts them as ready once they resolve and mount — you just drop the suspending component straight in:

<SuspenseRevealQueue interval={200}>
  <RevealSlot order={0} fallback={<ProfileSkeleton />}>
    <AsyncProfile />
  </RevealSlot>
  <RevealSlot order={1} fallback={<ChartSkeleton />}>
    <AsyncChart />
  </RevealSlot>
</SuspenseRevealQueue>

Props

SuspenseRevealQueue

PropTypeDefaultDescription
intervalnumber200Minimum interval between two consecutive reveals (milliseconds)
onRevealComplete() => voidFires once when every slot has been revealed
aria-labelstringAccessible label applied to the queue container
childrenReactNodeSeveral RevealSlot elements
classNamestringAppended to the container's class

RevealSlot

PropTypeDefaultDescription
ordernumberregistration orderReveal order (from 0; lower comes earlier); when omitted, numbering follows the DOM from top to bottom
fallbackReactNodeThe loading skeleton, shown before the content is revealed and faded out during the reveal
readybooleanControlled readiness flag; when omitted it switches to automatic mode (with a built-in Suspense)
childrenReactNodeThe real content, shown once ready
classNamestringAppended to the slot container's class

How it works

  • Joining the queue: any section joins the queue as soon as it is ready (ready flips to true, or in automatic mode Suspense resolves).
  • Revealing in order: the conductor reveals only one section at a time, with at least interval milliseconds between two reveals; the candidate is whichever has the lowest order among the "not yet revealed and already ready" sections.
  • No idle waiting: if a section earlier in the order is not ready yet, the conductor does not stall — it reveals the later sections that are ready first.
  • Automatic catch-up: an overtaken late section is added the moment it is ready, using a spring animation to signal "catching up", which distinguishes it from the smooth fade of a normal reveal.

Accessibility

  • The container carries role="group" and is marked aria-busy until everything has been revealed; you can add an aria-label explaining the purpose of the region.
  • Skeletons are marked aria-hidden so assistive technology never reads them.
  • Unrevealed content is isolated with aria-hidden and inert, so a section that is not yet shown cannot be read out or reached by keyboard focus.
  • When the user has "reduce motion" enabled at the system level, the paced choreography along with the displacement/blur are dropped and every ready section simply fades in.

On this page