AddThisFeature

Async Boundary Component

Give every asynchronous region the same set of states instead of hand-rolling each one.

involved Developer Experience

What it adds

A shared wrapper that renders pending, error, empty, refreshing, and ready for any region backed by a request.

What your agent is told to do

5
  1. 1

    Find the regions of the app that depend on a request — lists, detail panels, widgets, charts, dropdown options — and route each one through the shared boundary rather than a local set of flags.

  2. 2

    Model the states explicitly and exhaustively so that pending, error, empty, refreshing, and ready are the only possibilities, and the caller cannot render a sixth thing by accident.

  3. 3

    Distinguish the first load, which has nothing to show, from a refetch, which already has content. The first deserves a skeleton shaped like the eventual result; the second deserves a quiet indicator over what is already on screen.

  4. 4

    Make the empty state a first-class slot the caller fills, because an empty search result, an empty inbox, and a filtered-to-nothing table say different things and need different next actions.

  5. 5

    The mechanics of the state graph itself — legal transitions, cancellation, timeouts — belong to UI State Machine Pattern; this boundary owns what those states look like and where they are placed. Take the machine from there rather than defining a second one here.

Edge cases it handles

7
  • A background refresh must keep the previous content visible. Dropping back to a skeleton because a poll fired makes a stable screen flash for no reason, and it throws away the user's scroll position.
  • The initial load and a later refetch are not the same event and must not share one flag. Collapsing them is what produces a full-page spinner on every keystroke of a filter.
  • Every error state needs a retry that re-runs only that region's request, and every in-flight request needs to be cancellable when the user navigates away or changes the parameters underneath it.
  • Boundaries nest, and a parent skeleton wrapped around three child skeletons reads as a broken page. Decide which level owns the visible pending treatment and have the inner ones render nothing while the outer one is pending.
  • A request that resolves in twenty milliseconds should not flash a loader at all — hold the pending treatment behind a short delay, and once it is shown, keep it long enough not to strobe.
  • A response that arrives after its parameters have changed must be discarded, or a slow earlier request will overwrite the results of a newer one.
  • The transition into the ready state must not shift the page. Reserve the space the content will occupy so the skeleton and the result are the same size.

Definition of done

9
  • Every request-backed region in the app renders through the shared boundary.
  • Pending, error, empty, refreshing, and ready are the complete and only set of rendered states.
  • A background refresh leaves previous content and scroll position in place.
  • Errors offer a retry scoped to that region, and in-flight requests are cancelled on navigation or parameter change.
  • Nested boundaries produce a single pending treatment rather than stacked skeletons.
  • Fast responses complete without any loader appearing, and no loader flashes for less than its minimum duration.
  • The state machine is taken from UI State Machine Pattern rather than reimplemented.
  • The feature matches the existing design system.
  • No existing functionality is broken.

Related features

How it works

  1. 1

    Copy the link

    Grab the Markdown instruction URL for this feature.

  2. 2

    Give it to your AI

    Paste it into Claude Code, Cursor, v0, Lovable — whatever you build with.

  3. 3

    It inspects, then implements

    Your agent reads your existing app first, then adds the feature to fit it.

Works with your stack

These instructions are written to adapt. They tell the agent to detect your framework, match your existing design system, and reuse what you already have — rather than assuming a particular stack.

Need it tighter than that? Customize the feature and tell it exactly what you're running.