Toast
FreeA brief, non-modal notification that appears temporarily at the edge of the viewport to confirm an action or report a status change. Toasts auto-dismiss after 5 seconds by default, stack vertically when multiple appear, and include an optional dismiss button. Supports info, success, warning, and error severity levels. Error toasts must not auto-dismiss — they persist until the user explicitly closes them.
12 variants
Variants
| Variant | Description | When to use |
|---|---|---|
| Info | Blue-toned toast for neutral status updates. | Use for non-critical confirmations — "Link copied to clipboard", "Settings updated". |
| Success | Green-toned toast confirming a completed action. | Use after successful operations — "File uploaded", "Invitation sent". |
| Warning | Amber-toned toast for conditions that may need attention. | Use for non-blocking warnings — "You are approaching your usage limit". |
| Error | Red-toned toast for action failures. Does not auto-dismiss. | Use when an action fails — "Failed to save changes", "Network error". |
Usage Guidelines
Auto-dismiss info, success, and warning toasts after 5 seconds.
Use toasts for critical errors that require immediate user action — use Alert or a dialog.
Never auto-dismiss error toasts — they must persist until closed by the user.
Display more than 3 toasts simultaneously — queue excess toasts.
Use aria-live="polite" so screen readers announce the toast without interrupting.
Use toasts for information the user needs to reference later — it will disappear.
Stack multiple toasts vertically with the newest at the bottom.
Code
<div class="lex-toast-container" aria-live="polite" aria-atomic="true">
<div class="lex-toast lex-toast--success" role="status">
<svg class="lex-toast__icon" aria-hidden="true"><!-- check icon --></svg>
<p class="lex-toast__message">File uploaded successfully.</p>
<button class="lex-toast__close" aria-label="Dismiss notification">
<svg aria-hidden="true"><!-- close icon --></svg>
</button>
</div>
</div>
<div class="lex-toast lex-toast--error" role="alert">
<svg class="lex-toast__icon" aria-hidden="true"><!-- error icon --></svg>
<p class="lex-toast__message">Failed to save changes.</p>
<button class="lex-toast__action">Retry</button>
<button class="lex-toast__close" aria-label="Dismiss notification">
<svg aria-hidden="true"><!-- close icon --></svg>
</button>
</div>.lex-toast-container {
position: fixed;
bottom: var(--lex-space-24);
right: var(--lex-space-24);
display: flex;
flex-direction: column;
gap: var(--lex-space-8);
z-index: var(--lex-z-toast, 9000);
pointer-events: none;
}
.lex-toast {
display: flex;
align-items: center;
gap: var(--lex-space-8);
padding: var(--lex-space-12) var(--lex-space-16);
border-radius: var(--lex-radius-lg);
background: var(--lex-bg-surface-raised);
border: 1px solid var(--lex-toast-border);
box-shadow: var(--lex-shadow-lg);
pointer-events: auto;
animation: lex-toast-in 200ms ease-out;
}
.lex-toast--success { --lex-toast-border: var(--lex-border-success); }
.lex-toast--error { --lex-toast-border: var(--lex-border-danger); }
.lex-toast--warning { --lex-toast-border: var(--lex-border-warning); }
.lex-toast--info { --lex-toast-border: var(--lex-border-info); }
.lex-toast__icon {
flex-shrink: 0;
width: 20px;
height: 20px;
}
.lex-toast__message {
font-size: var(--lex-font-size-sm);
margin: 0;
flex: 1;
}
.lex-toast__action {
font-size: var(--lex-font-size-sm);
font-weight: 600;
color: var(--lex-text-brand);
background: none;
border: none;
cursor: pointer;
padding: 0;
white-space: nowrap;
}
.lex-toast__close {
flex-shrink: 0;
background: none;
border: none;
cursor: pointer;
color: var(--lex-text-muted);
}
@keyframes lex-toast-in {
from {
opacity: 0;
transform: translateY(8px);
}
to {
opacity: 1;
transform: translateY(0);
}
}// Using Lexicon CSS classes with React
export function UploadHandler() {
const handleUpload = async (file: File) => {
try {
await uploadFile(file);
toast.success('File uploaded successfully.');
} catch (err) {
toast.error('Failed to upload file.', {
action: { label: 'Retry', onClick: () => handleUpload(file) },
});
}
};
return <UploadArea onUpload={handleUpload} />;
}
// Toast with undo action
function DeleteItem({ id }: { id: string }) {
const handleDelete = async () => {
await deleteItem(id);
toast.success('Item deleted.', {
action: { label: 'Undo', onClick: () => restoreItem(id) },
});
};
return <Button variant="danger" onClick={handleDelete}>Delete</Button>;
}Design Tokens
| Token | Value (dark) | Value (light) | CSS property |
|---|---|---|---|
| --lex-toast-bg | — | — | bg |
| --lex-toast-border | — | — | border |
| --lex-toast-radius | — | — | radius |
| --lex-toast-shadow | — | — | shadow |
| --lex-toast-padding | — | — | padding |
Accessibility
- Toast container uses aria-live="polite" so announcements do not interrupt the user.
- Error toasts should use role="alert" for a more assertive announcement.
- Never auto-dismiss error toasts — they must persist until manually closed.
- Dismiss button requires aria-label="Dismiss notification".
- Action buttons inside toasts must be keyboard-accessible.
- Pause the auto-dismiss timer when the user hovers over or focuses within the toast.