<!-- Generated by emit-docs.ts — do not edit. -->
# Toast

A single transient notification card (D64). Controlled and presentational: it holds no state, runs no timer, and never removes itself — `onDismiss` reports and the owner disposes, exactly as Dialog (D50) and Menu (D53) do. Toast does not carry its own `role`/`aria-live`. Politeness belongs to the two persistent wrappers inside ToastRegion, because a live region must pre-exist the content it announces; a role on the toast itself would reintroduce the mount-with-content problem one level down. Composed by hand with ToastRegion for full control, or driven by ToastProvider's queue.

## Props

| Prop | Type | Default | Required | Description |
|---|---|---|---|---|
| `variant` | `"neutral" \| "success" \| "warning" \| "danger"` | neutral | no | Status variant. |
| `children` | `ReactNode` | — | yes | The message. |
| `action` | `ReactNode` | — | no | Trailing affordance — a ghost Button (Undo, Retry, View). |
| `onDismiss` | `(() => void)` | — | no | When provided, renders the dismiss button and calls this. Toast does not remove itself; the owner disposes. |
| `className` | `string` | — | no | Additional CSS class name(s) merged onto the component's root element. |
| `ref` | `Ref<HTMLDivElement>` | — | no | Forwarded ref to the underlying `<div>`. |

## Keyboard & assistive tech

| Keys | Behavior |
|---|---|
| Tab | Reaches the action and the dismiss button in DOM order. Esc is not a dismissal — a toast is not modal and traps nothing. |
| Enter / Space | Activates the focused action or dismiss button. |

Presentational and controlled (D64): onDismiss reports and the owner disposes; Toast never removes itself. It carries no role/aria-live of its own — politeness belongs to ToastRegion's two persistent wrappers. The variant's meaning is announced by a visually hidden status word ("Success:", "Warning:", "Error:"), never by colour and icon shape alone; the icon is aria-hidden. neutral has no status and gets no prefix. The dismiss button requires no props — it is labelled "Dismiss notification".

## Theming

Override `--psi-toast-*` custom properties at any scope.

## Variant guidance

- **accent** — Primary action, draws attention. Submit, CTA, main action in a group.
- **accent-subtle** — Accent tone, lower visual weight. Selected state, active filter, soft CTA.
- **neutral** — Default, structurally present. Secondary actions, toolbar buttons.
- **neutral-subtle** — Minimal chrome. Inline actions, table row actions.
- **ghost** — No visible container until hover. Icon-only triggers, compact toolbars.
- **outline** — Bordered ghost — visible structure, no fill until hover. Marketing CTA, download button; hover fills accent.
- **danger** — Destructive action. Delete, remove, disconnect.
- **danger-subtle** — Destructive context, low urgency. Warning badges, soft destructive hints.
- **success | warning** — Status communication (Tag only). Status badges, labels.

## Rules

- One accent per visual group; everything else neutral or ghost.
- danger only for actions with real consequences.
- Sizes are px numbers (24|32|40|48), never S/M/L.
- Typography tokens are --psi-text-{size}-{lineHeight}-{weight}.
- Override component tokens (--psi-{component}-*), not semantic tokens, for one-off theming.
- --psi-button-font overrides button typography across all sizes (documented D34 override; ember → mono).
- Wrap labeled form controls in Field — label association, description/error line, aria-describedby and aria-invalid come wired; don't hand-roll label+message rows.
- Field is for a control with a *visible* label. A toolbar filter control named by aria-label or placeholder takes neither a Field nor a hand-rolled label row — compare filter-toolbar (no labels) with table-pagination ("Rows per page" visible, so Field).
- Use Dialog for blocking modal flows — title/footer slots, dismissible gate; danger stays on the footer Buttons, one accent per group.
