Toast
since v0.3.0Transient notification bar — use for non-blocking operation feedback.
Forwards ref to the root live-region <div role={status|alert}> (always mounted).
Install
Add the package and import the component.
pnpm add @hey-mike/tungstenpnpm add @hey-mike/tungstenimport { Toast } from '@hey-mike/tungsten';import { Toast } from '@hey-mike/tungsten';Preview
Same fixtures used by the visual-regression suite.
Usage
apps/docs/app/snapshots/toast/page.tsx
'use client';
import { Toast } from '@hey-mike/tungsten';
const variants = [
{ label: 'default', node: <Toast message="Saved." onDismiss={() => undefined} /> },
{
label: 'success',
node: <Toast variant="success" message="Imported 12 rows." onDismiss={() => undefined} />,
},
{
label: 'error',
node: <Toast variant="error" message="Upload failed. Try again." onDismiss={() => undefined} />,
},
{
label: 'with-undo',
node: <Toast message="Item deleted." onUndo={() => undefined} onDismiss={() => undefined} />,
},
];
export default function ToastSnapshot() {
return (
<main data-testid="snapshot-root" className="bg-page text-ink-1 min-h-screen p-8">
<h1 className="text-ink-2 mb-6 font-mono text-sm uppercase tracking-widest">Toast</h1>
<dl className="flex flex-col gap-3">
{variants.map(({ label, node }) => (
<div key={label} className="flex items-center gap-6">
<dt className="text-ink-3 font-mono text-xs w-20 shrink-0">{label}</dt>
{/*
* transform: translateZ(0) makes this element a containing block for
* position:fixed descendants — Toast's fixed/inset-x-0/bottom-6 then
* positions relative to this dd instead of the viewport.
*/}
<dd className="m-0 flex-1 relative h-20" style={{ transform: 'translateZ(0)' }}>
{node}
</dd>
</div>
))}
</dl>
</main>
);
}
'use client';
import { Toast } from '@hey-mike/tungsten';
const variants = [
{ label: 'default', node: <Toast message="Saved." onDismiss={() => undefined} /> },
{
label: 'success',
node: <Toast variant="success" message="Imported 12 rows." onDismiss={() => undefined} />,
},
{
label: 'error',
node: <Toast variant="error" message="Upload failed. Try again." onDismiss={() => undefined} />,
},
{
label: 'with-undo',
node: <Toast message="Item deleted." onUndo={() => undefined} onDismiss={() => undefined} />,
},
];
export default function ToastSnapshot() {
return (
<main data-testid="snapshot-root" className="bg-page text-ink-1 min-h-screen p-8">
<h1 className="text-ink-2 mb-6 font-mono text-sm uppercase tracking-widest">Toast</h1>
<dl className="flex flex-col gap-3">
{variants.map(({ label, node }) => (
<div key={label} className="flex items-center gap-6">
<dt className="text-ink-3 font-mono text-xs w-20 shrink-0">{label}</dt>
{/*
* transform: translateZ(0) makes this element a containing block for
* position:fixed descendants — Toast's fixed/inset-x-0/bottom-6 then
* positions relative to this dd instead of the viewport.
*/}
<dd className="m-0 flex-1 relative h-20" style={{ transform: 'translateZ(0)' }}>
{node}
</dd>
</div>
))}
</dl>
</main>
);
}
Props
Surface specific to <Toast />.
| Prop | Type | Default | Description |
|---|---|---|---|
| message* | string | — | — |
| onUndo | (() => void) | — | — |
| onDismiss* | () => void | — | — |
| variant | "default" | "success" | "error" | default | Visual and semantic variant. Do not change while the toast is mounted — screen readers cache live-region metadata on registration. |
| visible | boolean | true | Controls mount/unmount with an animated enter/exit. Pass false to hide. Defaults to true (always shown). |
| icon | ReactElement<unknown, string | JSXElementConstructor<any>> | null | — | Override the default status icon. Pass null to suppress the icon entirely. default variant has no default icon. |
| duration | number | — | Auto-dismiss delay in ms. The component owns a timer only when this is a finite positive number; omit / Infinity / 0 / negative / NaN all mean no auto-dismiss (the consumer owns dismissal). Pair with {@link ToastProps.pauseOnHover} so an auto-dismissing toast can satisfy WCAG 2.2.1 (Timing Adjustable), which applies once a timeout exceeds 20s. |
| pauseOnHover | boolean | true | When auto-dismissing, pause the timer while the toast is hovered or keyboard-focused and resume on leave/blur — the conventional name covers focus too, so keyboard users aren't excluded. false disables both. Default true. No effect without duration. |