# Show a toast while a promise runs

> Report the loading, success and failure of one async call with toast.promise.

Source: https://platform.azmara.io/docs/recipes/toast-on-promise

Pass the promise to `toast.promise` with a message for each outcome. One toast moves from loading to success or error, so nothing stacks up.

```tsx
"use client";

import { Button } from "@azmr/ui/button";
import { toast } from "@azmr/ui/toast";

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

export default function ToastPromise() {
  return (
    <div className="flex flex-wrap gap-2">
      <Button
        variant="outline"
        onClick={() =>
          toast.promise(
            wait(1500).then(() => 12),
            {
              loading: "Exporting…",
              success: (rows) => `Exported ${rows} rows`,
              error: "Export failed",
            },
          )
        }
      >
        Export (succeeds)
      </Button>
      <Button
        variant="outline"
        onClick={() =>
          toast
            .promise(
              wait(1500).then(() => Promise.reject(new Error("Disk full"))),
              {
                loading: "Exporting…",
                success: "Exported",
                error: (e: Error) => `Export failed: ${e.message}`,
              },
            )
            .catch(() => {})
        }
      >
        Export (fails)
      </Button>
    </div>
  );
}
```

## The pattern

```tsx
import { toast } from "@azmr/ui/toast";

toast.promise(save(), {
  loading: "Saving…",
  success: (rows) => `Saved ${rows} rows`,
  error: (e: Error) => `Could not save: ${e.message}`,
});
```

- `success` and `error` can be a string or a function of the resolved value or the error.
- A rejected promise is still rejected for you: `toast.promise` returns the promise, so catch it (`.catch(() => {})`) if you have nothing more to do, as the failing button above does.
- Toasts are announced by a polite live region and do not move focus, so the person keeps typing.
- Mount one [`Toaster`](https://platform.azmara.io/docs/components/toast.md) near the root of the app. Toasts show for a few seconds, so use one only for something that needs no decision. If the person has to choose, use a dialog.

For a toast with an action, such as Undo, see the [confirm-delete example](https://platform.azmara.io/docs/examples/confirm-delete-flow.md).
