Pho Design System

Toast

A transient, non-blocking notification — confirmation of a background action, a brief status update. Built on Base UI Toast, which is driven imperatively through a manager. For a choice the user must make, use Dialog.

Import

import { Toast, Toasty } from "@photon-ai/pho-ui/components/toast";

Basic

Wrap the tree in Toast.Provider, render a Toast.Viewport that maps useToastManager().toasts to Toast.Roots, then call add() to show one.

function ToastList() {
  const { toasts } = Toast.useToastManager();
  return toasts.map((toast) => (
    <Toast.Root key={toast.id} toast={toast}>
      <Toast.Content>
        <Toast.Title />
        <Toast.Description />
      </Toast.Content>
      <Toast.Close aria-label="Dismiss">
        <X />
      </Toast.Close>
    </Toast.Root>
  ));
}

function App() {
  const toast = Toast.useToastManager();
  return (
    <Toast.Provider>
      <Button onClick={() => toast.add({ title: "Deployment ready" })}>
        Deploy
      </Button>
      <Toast.Portal>
        <Toast.Viewport>
          <ToastList />
        </Toast.Viewport>
      </Toast.Portal>
    </Toast.Provider>
  );
}

Types

type picks the status ink — success, error, warning, info — and tints the hairline, the glyph, and the title together, with a breath of the same ink washed over the surface. info speaks in the brand ink.

Action

Pass actionProps when you enqueue a toast and render a Toast.Action that spreads them — one undo/retry affordance whose click also dismisses the toast. Keep it to a single action; anything more is a dialog.

// In the list:
<Toast.Content>
  <Toast.Title />
  <Toast.Description />
  {toast.actionProps ? <Toast.Action {...toast.actionProps} /> : null}
</Toast.Content>;

// Firing one:
manager.add({
  title: "Project deleted",
  actionProps: { children: "Undo", onClick: restore },
});

Stacking

Toasts rest as a stack, Kumo’s math: each card behind rises 12px at −10% scale per depth, its words hidden behind the front card — at most three visible (the provider’s limit; the rest park until room frees). Hover or focus the stack and it expands into a true list with a 12px gap; swipe a card to dismiss it. New cards rise in from below and leave the same way.

Promise

manager.promise walks one card through the work: loading shows the spinner, then the card becomes the success or error outcome in place.

Anatomy

Props

Every rendered part also accepts className and render (Base UI’s prop for swapping the underlying element).

Toast.Provider

useToastManager().add(options) — enqueue a toast

The manager also returns close(id?), update(id, options), and promise(promise, { loading, success, error }).

Toast.Root (<div role="dialog">)

Accessibility

Best practices