Toast
A short note, bottom right, that something just happened: a save, a move, an archive. It states the fact in the past tense and offers Undo when the action can be reversed.
Playground
Change the controls to try each option. The preview holds the toast open; on a page a toast closes after 5 seconds, and an error stays until closed. The code under the preview is the call to copy.
import { toast } from '@/ui/toast';toast.add({ type: "success", title: "Company added",});Types
Press a button to show its toast, bottom right. Success confirms a save the person can't see change. Error says what failed and what to do, and stays until closed. Information is a neutral fact; warning is a result with a catch.
import { Button } from '@/ui/button';
import { toast } from '@/ui/toast';
export default function ToastTypes() {
return (
<div className="flex flex-wrap items-center justify-center gap-100">
<Button onClick={() => toast.add({ type: 'success', title: 'Company added' })}>Success</Button>
<Button
onClick={() =>
toast.add({ type: 'error', title: 'Stage not saved', description: 'Check your connection and try again.' })
}
>
Error
</Button>
<Button onClick={() => toast.add({ type: 'info', title: 'Link copied' })}>Information</Button>
<Button onClick={() => toast.add({ type: 'warning', title: 'Saved, but 3 rows were skipped' })}>Warning</Button>
</div>
);
}Undo
A reversible action happens at once and offers Undo. The button shows ⌘Z (Ctrl+Z on Windows and Linux), and that shortcut presses the newest Undo from anywhere outside a text field.
import { ArchiveIcon } from '@phosphor-icons/react';
import { Button } from '@/ui/button';
import { toast } from '@/ui/toast';
export default function ToastUndo() {
function archive() {
// Archive at once, then offer the way back. ⌘Z presses the newest Undo.
const id = toast.add({
type: 'success',
title: 'Halcyon Bank archived',
actionProps: {
children: 'Undo',
onClick: () => {
toast.close(id);
toast.add({ type: 'success', title: 'Halcyon Bank restored' });
},
},
});
}
return (
<Button onClick={archive}>
<ArchiveIcon />
Archive company
</Button>
);
}Loading
For work that takes a while, toast.promise shows a loading toast that turns into the success or error toast in place.
import { UploadSimpleIcon } from '@phosphor-icons/react';
import { Button } from '@/ui/button';
import { toast } from '@/ui/toast';
const importCompanies = () => new Promise((resolve) => setTimeout(resolve, 2000));
export default function ToastLoading() {
return (
<Button
onClick={() =>
toast.promise(importCompanies(), {
loading: { title: 'Importing 240 companies' },
success: { title: '240 companies imported' },
error: { title: 'Import failed', description: 'Nothing was added. Check the file and try again.' },
})
}
>
<UploadSimpleIcon />
Import companies
</Button>
);
}