@jarvis-ui
GitHub

Toast

A stacked toast manager built on Base UI with promise helpers, inline actions, and optional expandable details.

Installation

npx shadcn@latest add https://ui.jarv.is/r/toast.json

Usage

App root setup

Render one Toaster near your React app root, then call toast from any client component.

import { StrictMode } from "react";
import { createRoot } from "react-dom/client";

import { Toaster } from "@/components/ui/toast";
import { App } from "./app";
import "./index.css";

createRoot(document.getElementById("root")!).render(
  <StrictMode>
    <App />
    <Toaster closeButton richColors position="bottom-right" />
  </StrictMode>,
);

Basic feedback

Use basic typed toasts for routine product feedback.

import { toast } from "@/components/ui/toast";

export function SaveButton() {
  return <button onClick={() => toast.success("Saved")}>Save</button>;
}

Descriptions

Add descriptions when the user needs context, not just confirmation.

toast.success("Deployment complete", {
  description: "Production is now serving build 1042.",
});

toast.warning("Verification paused", {
  description: "A required secret is missing for the production smoke test.",
});

Actions

Use actions for reversible operations or next steps.

toast.info("Invite copied", {
  action: {
    label: "Undo",
    onClick: () => {
      void restoreInvite(inviteId);
    },
  },
});

Promise states

Use toast.promise when a toast should track an async operation from loading to final state.

await toast.promise(publishRelease(), {
  loading: {
    title: "Publishing release",
    description: "Uploading assets and warming the deployment.",
  },
  success: (release) => ({
    title: "Release published",
    description: `${release.version} is live in production.`,
  }),
  error: (error) => ({
    title: "Publish failed",
    description: error instanceof Error ? error.message : "Try again from the releases page.",
  }),
});

Error details

Error toasts with string descriptions include a copy-details button by default. Set hideCopyButton when copying the description is not useful.

toast.error("Upload failed", {
  description:
    "The source map upload hit a permissions error. Re-authenticate the CI token and retry.",
  closeButton: true,
});

Expandable details

Use expandable content for diagnostics, checklists, or secondary detail that should not dominate the collapsed toast.

toast.warning("Verification paused", {
  description: "A required secret is missing for the production smoke test.",
  actionLayout: "stacked-end",
  actionVariant: "outline",
  action: {
    label: "Open checklist",
    onClick: () => openDeploymentChecklist(),
  },
  expandableContent: (
    <ul>
      <li>`VERCEL_TOKEN` is not configured for this environment.</li>
      <li>`POSTHOG_API_KEY` is missing from the deployment step.</li>
      <li>Smoke tests were skipped after the build artifact upload.</li>
    </ul>
  ),
});

Manual dismissal

Use a longer-lived loading toast when work crosses screens, then dismiss it explicitly.

const toastId = toast.loading("Syncing workspace", {
  description: "This can take a few seconds.",
  duration: 30_000,
});

try {
  await syncWorkspace();
  toast.success("Workspace synced");
} finally {
  toast.dismiss(toastId);
}

API

Refer to the Base UI documentation for more details.