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 } 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>
  );
}

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 },
});

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