Toast
Toasts driven by ToastProvider and useToast: a stacking portal, auto-dismiss, hover pause.
Installation
Add component
pnpm dlx @elyri/cli@latest add toastExamples
Basic
Call toast({ title, description, variant }) to push a toast.
import { ToastProvider, useToast } from './components/elyri/Toast';
import { Button } from './components/elyri/Button';
function Trigger() {
const { toast } = useToast();
return (
<Button
onClick={() => toast({ title: 'Saved', description: 'Saved to your workspace.', variant: 'success' })}
>
Show toast
</Button>
);
}
export function Example() {
return (
<ToastProvider>
<Trigger />
</ToastProvider>
);
}Position
Switch the ToastProvider position to dock toasts to any of the six viewport corners.
import { useState } from 'react';
import { ToastProvider, useToast } from './components/elyri/Toast';
import type { ToastPosition } from './components/elyri/Toast';
import { Button } from './components/elyri/Button';
const positions: ToastPosition[] = ['top-left', 'top', 'top-right', 'bottom-left', 'bottom', 'bottom-right'];
function Trigger({ position, onPick }: { position: ToastPosition; onPick: (position: ToastPosition) => void }) {
const { toast } = useToast();
return (
<div className="demo-ui-row">
{positions.map((item) => (
<Button
key={item}
variant={item === position ? 'primary' : 'secondary'}
onClick={() => {
onPick(item);
toast({ title: 'Position', description: item, variant: 'info' });
}}
>
{item}
</Button>
))}
</div>
);
}
export function Example() {
const [position, setPosition] = useState<ToastPosition>('top');
return (
<ToastProvider position={position}>
<Trigger position={position} onPick={setPosition} />
</ToastProvider>
);
}Variants
Four variants: info / success / warning / danger.
import { ToastProvider, useToast } from './components/elyri/Toast';
import { Button } from './components/elyri/Button';
function Trigger() {
const { toast } = useToast();
return (
<div className="demo-ui-row">
<Button onClick={() => toast({ title: 'Heads up', description: 'A neutral update.', variant: 'info' })}>
Info
</Button>
<Button onClick={() => toast({ title: 'Saved', description: 'Saved to your workspace.', variant: 'success' })}>
Success
</Button>
<Button onClick={() => toast({ title: 'Careful', description: 'This is irreversible.', variant: 'warning' })}>
Warning
</Button>
<Button onClick={() => toast({ title: 'Error', description: 'Something went wrong.', variant: 'danger' })}>
Danger
</Button>
</div>
);
}
export function Example() {
return (
<ToastProvider>
<Trigger />
</ToastProvider>
);
}Loading → Success
Push a loading toast, then update it in place to success with update(id, options).
import { ToastProvider, useToast } from './components/elyri/Toast';
import { Button } from './components/elyri/Button';
function Trigger() {
const { toast, update } = useToast();
const showLoading = () => {
const id = toast({ title: 'Uploading file', description: 'Please wait…', variant: 'loading' });
setTimeout(
() => update(id, { title: 'Upload complete', description: 'Saved to your workspace.', variant: 'success' }),
1500,
);
};
return <Button onClick={showLoading}>Upload file</Button>;
}
export function Example() {
return (
<ToastProvider>
<Trigger />
</ToastProvider>
);
}Single-line Message
Omit description to show a single-line title; push a loading message, then update it to danger.
import { ToastProvider, useToast } from './components/elyri/Toast';
import { Button } from './components/elyri/Button';
function Trigger() {
const { toast, update } = useToast();
const showMessage = () => {
const id = toast({ title: 'Connecting…', variant: 'loading' });
setTimeout(() => update(id, { title: 'Connection failed', variant: 'danger' }), 1500);
};
return <Button onClick={showMessage}>Connect</Button>;
}
export function Example() {
return (
<ToastProvider>
<Trigger />
</ToastProvider>
);
}Promise
promise(p, messages) follows a promise and switches loading / success / error.
import { ToastProvider, useToast } from './components/elyri/Toast';
import { Button } from './components/elyri/Button';
function Trigger() {
const { promise } = useToast();
const showPromise = () => {
promise(new Promise((resolve) => setTimeout(resolve, 1500)), {
loading: { title: 'Submitting', description: 'Hang tight…' },
success: { title: 'Submitted', description: 'Saved to your workspace.' },
error: { title: 'Submit failed', description: 'Please try again.' },
});
};
return <Button onClick={showPromise}>Submit</Button>;
}
export function Example() {
return (
<ToastProvider>
<Trigger />
</ToastProvider>
);
}Persistent
A persistent: true toast never auto-dismisses; close it with dismiss(id).
import { ToastProvider, useToast } from './components/elyri/Toast';
import { Button } from './components/elyri/Button';
function Trigger() {
const { toast, dismiss } = useToast();
const showPersistent = () => {
const id = toast({
title: 'Syncing',
description: 'Closed by the app when the task finishes.',
variant: 'loading',
persistent: true,
});
setTimeout(() => dismiss(id), 3000);
};
return <Button onClick={showPersistent}>Start sync</Button>;
}
export function Example() {
return (
<ToastProvider>
<Trigger />
</ToastProvider>
);
}Props
| Prop | Type | Default | Description |
|---|---|---|---|
ToastProvider.duration | number | 4000 | Default auto-dismiss delay, 0 keeps the toast until dismissed |
ToastProvider.limit | number | 4 | Maximum number of toasts shown at once |
ToastProvider.position | ToastPosition | 'top' | Viewport docking direction, six options, defaults to top |
ToastProvider.label | string | 'Notifications' | Accessible name of the viewport region |
ToastProvider.onClose | (id, reason) => void | — | Called when any toast closes, with reason manual | timeout | limit |
useToast().toast | (options) => string | — | toast(options) pushes a toast and returns its id |
useToast().update | (id, options) => void | — | update(id, options) updates an existing toast in place, e.g. loading to success |
useToast().dismiss | (id?: string) => void | — | dismiss(id) closes a single toast; call it without an id to close them all |
useToast().promise | (p, messages) => Promise | — | promise(p, { loading, success, error }) tracks a promise and switches loading / success / error |
options | ToastOptions | — | toast options: title / description / variant / duration / persistent / dismissible / action |
options.description | ReactNode | — | When off, the description is hidden and the toast shrinks to a single-line message |
options.persistent | boolean | false | Pinned toast: never auto-dismisses, hides the close button and is never evicted by limit; close it with dismiss(id) |
options.dismissible | boolean | true | Whether the close button shows, defaults to true; always hidden when persistent |
children | ReactNode | — | Provider wraps your application |