Browse guides

Represent content that is still resolving

Define what an asynchronous screen shows while loading, when it completes, and when an error occurs.

The example waits before resolving the profile so fallback remains visible. Its two actions start a successful run or a rejected run with a fresh suspenseKey.

Table of contents

Main APIs

Suspense
Renders fallback while asynchronous children resolve, then renders the result or error output.
tsx
import { mount } from "valyrian.js";
import { Suspense } from "valyrian.js/suspense";

type Outcome = "success" | "error";

const state = { outcome: "success" as Outcome, run: 0 };

const wait = (milliseconds: number) =>
  new Promise((resolve) => setTimeout(resolve, milliseconds));

async function Profile({ outcome }: { outcome: Outcome }) {
  await wait(700);
  if (outcome === "error") {
    throw new Error("Profile request failed");
  }
  return <p>Loaded profile</p>;
}

function load(outcome: Outcome) {
  state.outcome = outcome;
  state.run += 1;
}

const Screen = () => {
  const suspenseKey = `profile:${state.outcome}:${state.run}`;
  return (
    <main>
      <button onclick={() => load("success")}>Load profile</button>
      <button onclick={() => load("error")}>Load rejected profile</button>
      <Suspense
        suspenseKey={suspenseKey}
        fallback={<p>Loading profile...</p>}
        error={(error) => <p>{String(error)}</p>}
      >
        <Profile outcome={state.outcome} />
      </Suspense>
    </main>
  );
};

mount("body", Screen);

Error

The `error` renderer produces the failure output when an asynchronous child rejects.

Apply this concept in Taskboard

API reference