# Toast

Package: @commenda/pathfinder@0.1.0
Page: /docs/components/toast
Figma: https://www.figma.com/design/dn7BkGYEfIyP0o2zfesfVh/The-System?node-id=316-2

```tsx
import { Toaster, toast } from '@commenda/pathfinder/toast';
// Mount Toaster once in your application shell.
<>
  <Toaster />
  <Button
    onClick={() =>
      toast.show({
        title: 'Updated filing',
        description: 'Your filing details are up to date.',
        tone: 'success',
      })
    }
  >
    Show success
  </Button>
</>;
```


## Installation [#installation]

```sh
pnpm --filter your-app add "@commenda/pathfinder@workspace:*"
```

Import `@commenda/pathfinder/styles.css` once after host CSS. Styles are precompiled with Tailwind v4; consumers need no Tailwind scanning. Interactive callbacks belong in client components in Next.js App Router.

## Usage [#usage]

```tsx
import { Toaster, toast } from '@commenda/pathfinder/toast';
// Mount Toaster once in your application shell.
<>
  <Toaster />
  <Button
    onClick={() =>
      toast.show({
        title: 'Updated filing',
        description: 'Your filing details are up to date.',
        tone: 'success',
      })
    }
  >
    Show success
  </Button>
</>;
```

## API reference [#api-reference]

| Prop                        | Type                                                        | Default / behavior                                |
| --------------------------- | ----------------------------------------------------------- | ------------------------------------------------- |
| `Toaster.label`             | `string`                                                    | Notifications; Alt+T enters stack                 |
| `Toaster.direction`         | `ltr \| rtl \| auto`                                        | auto                                              |
| `toast.show(options)`       | `ToastId`                                                   | Creates a notification                            |
| `toast.update(id, options)` | `ToastId`                                                   | Replaces the same notification; pass full options |
| `toast.dismiss(id?)`        | `void`                                                      | Dismisses one or all Pathfinder notifications     |
| `title`                     | `string`                                                    | Required, past tense, sentence case               |
| `description`               | `string`                                                    | Optional concise supporting copy                  |
| `tone`                      | `neutral \| success \| info \| warning \| error \| loading` | neutral                                           |
| `id`                        | `string`                                                    | Optional stable task identifier                   |
| `actionConfig`              | `FeedbackAction & { appearance?: link \| secondary }`       | One action; secondary only for neutral            |
| `onDismiss`                 | `(reason: manual \| timeout \| swipe) => void`              | Notification removed from the active queue        |

Mount one Toaster in the application shell. Import Pathfinder styles once; no extra Sonner CSS is required. Neutral, success and info expire after 4 seconds; warning, error and loading persist. Hover, keyboard focus, hidden documents and queued messages pause expiry. Replace loading in place with update; never show a second result notification. Body clicks do not dismiss. Actions do not dismiss automatically: call toast.dismiss(id) when appropriate. Never put form validation or required decisions in a toast. This wrapper does not migrate or clear the application’s existing Sonner notifications.

### Actions [#actions]

`FeedbackAction` requires a label and exactly one of `onClick` (command) or `href` (native navigation). Commands support `disabled`, `disabledReason`, `loadingConfig`, and `leadingIcon`; navigation supports `target`, `rel`, and `leadingIcon`. The application owns async work and retry state.

## Examples [#examples]

### Tones [#tones]


```tsx
<>
  {(['neutral', 'info', 'success', 'warning', 'error', 'loading'] as const).map(
    (tone) => (
      <Button
        key={tone}
        onClick={() =>
          toast.show({
            title: tone === 'loading' ? 'Submitting filing' : 'Updated filing',
            description: 'Your filing details are up to date.',
            tone,
          })
        }
      >
        Show {tone}
      </Button>
    )
  )}
</>;
```


### Actions [#actions-1]


```tsx
import { Button } from '@commenda/pathfinder/button';
import { toast } from '@commenda/pathfinder/toast';
// Mount Toaster once in the application shell.
<>
  <Button
    variant="secondary"
    onClick={() => {
      toast.show({
        id: 'archive',
        title: 'Filing archived',
        tone: 'neutral',
        actionConfig: {
          label: 'Undo',
          appearance: 'secondary',
          onClick: () => {
            toast.update('archive', {
              title: 'Filing restored',
              tone: 'success',
            });
          },
        },
      });
    }}
  >
    Show Undo
  </Button>
  <Button
    variant="secondary"
    onClick={() => {
      toast.show({
        title: 'Report is ready',
        tone: 'info',
        actionConfig: { label: 'View report', href: '#usage' },
      });
    }}
  >
    Show link
  </Button>
  <Button
    variant="secondary"
    onClick={() => {
      toast.show({
        id: 'retry',
        title: 'Upload failed',
        tone: 'error',
        actionConfig: {
          label: 'Try again',
          onClick: () => {
            toast.update('retry', {
              title: 'Uploading files',
              tone: 'loading',
            });
          },
        },
      });
    }}
  >
    Show retry
  </Button>
</>;
```


### Update [#update]


```tsx
<>
  <Button
    onClick={() =>
      toast.show({ id: 'filing', title: 'Submitting filing', tone: 'loading' })
    }
  >
    Start submission
  </Button>
  <Button
    onClick={() =>
      toast.update('filing', { title: 'Filing submitted', tone: 'success' })
    }
  >
    Complete submission
  </Button>
</>;
```


Read the [design guidance](/docs/components/toast#design-rules) before using these components.

## Design rules [#design-rules]

Figma guidance and reviewed implementation decisions for this component. Rule IDs remain stable for source comments and AI references.

### Toast — 316:2 [#toast--3162]

- **TOAST-01:** Confirm a recent save, send or copy. Required decisions and durable problems belong in inline Alert. Never use a toast for form validation. Title uses past tense, sentence case, no period; description adds concise supporting text.
- **TOAST-02:** Neutral has no icon; success/info/warning/error use the solid 16 px glyphs from 464:357, not outline substitutes. Neutral/info/success expire after 4 seconds; warning/error/loading persist. Pause on hover, keyboard focus or hidden document. Queued messages get their reading time once visible.
- **TOAST-03:** Loading updates to its result under the same ID. One action maximum, normally a link; never a primary Button. Actions only dismiss when application code requests it. Body clicks do not dismiss.
- **TOAST-04:** Bottom center above overlays; three visible, newest in front. Collapsed peek 14 px at 0.95 scale; expanded gap 8. Width 356 with viewport/safe-area caps, white background, pearl 300 hairline, radius 10, panel elevation, padding 12/16, gap 10. Enter 400 ms ease-out, exit 200 ms; honor reduced motion. Close has a 16 px visible circle and a larger target. Alt+T enters the stack.
- **TOAST-05:** Mount one Pathfinder Toaster. A dedicated Sonner toaster ID and prefixed notification IDs isolate notifications from the existing application toaster. Pathfinder dismiss-all only dismisses its own active IDs. The scoped upstream structural stylesheet is a documented adapter exception to utility-only component styling; applications import only Pathfinder's finished CSS.
