Composite
Toast Requires JS
Transient notifications that appear in a corner of the screen and dismiss themselves after a few seconds. Announced to screen readers via live regions, dismissible by swipe / click, and stackable when several fire at once.
About
Overview
Use toasts for low-importance, transient feedback: "Saved", "Copied to clipboard", "Connection restored". They're the right primitive when you need to acknowledge an action without interrupting the user's flow. For high-stakes feedback (errors that block a flow), use a Dialog or an inline error message inside a Form Field instead.
Don't put critical actions in a toast. Toasts disappear; users miss them. If the user must read the message or perform an action in response, use a Dialog. Toast is for fire-and-forget acknowledgement.
Parts
Anatomy
A toast lives in a fixed-position viewport (one per corner of the screen) and contains an icon, title, optional description, and an optional action.
Project saved
Your changes are visible to the team.
Live
Demo
Trigger a toast from the buttons below. The viewport renders in the bottom-right corner of this page; toasts auto-dismiss after 4 seconds, or click the × to dismiss early.
// Imperative API — most common usage
window.toast.success('Project saved', { description: 'Your changes are live.' });
window.toast.info('Sync started');
window.toast.warning('Rate limit approaching');
window.toast.danger('Delete failed', { description: 'Please try again.' });
window.toast.show({ title: 'Email sent', action: { label: 'Undo', onClick: () => rollback() } });
Shapes
Variants
Four status variants: success, info, warning, danger. Each tints the icon and the left border in the matching semantic color.
The viewport supports six positions via data-position: top-right, top-left, top-center, bottom-right (default), bottom-left, bottom-center. Pick one for your whole app.
Add an inline action button — Undo, Retry, View. Best paired with a slightly longer auto-dismiss timeout so the user has time to react.
Set duration: 0 to disable auto-dismiss — the user must close it manually. Use sparingly; reserve for important state changes the user has to acknowledge.
Reference
API
CSS classes
| Class | Effect |
|---|---|
.ren-toast-viewport | Fixed-position container. One per app, picks a corner via data-position. Has aria-live="polite" so screen readers announce additions. |
.ren-toast | Single notification. Card-like surface with shadow. Slides in from the viewport's edge. |
.ren-toast-icon | Leading status icon. Color matches the toast's variant. |
.ren-toast-body | Title + optional description region. |
.ren-toast-title | The bold one-line message. |
.ren-toast-description | Secondary line with detail. Muted color. |
.ren-toast-action | Inline action button. Use a real <button>; pair with a callback in the JS API. |
.ren-toast-close | Dismiss × button. Always present, sized to be tappable on touch. |
JavaScript API
The component exposes a global window.toast with one method per status, plus a generic show(). Status methods return an id you can later pass to toast.dismiss(id).
| Method | Returns | Description |
|---|---|---|
toast.success(title, options?) | string (id) | Green check, polite announce. |
toast.info(title, options?) | string (id) | Blue info, polite. |
toast.warning(title, options?) | string (id) | Amber, polite. |
toast.danger(title, options?) | string (id) | Red, assertive announce — screen readers interrupt. |
toast.show(options) | string (id) | Full control. { title, description, status, duration, action }. |
toast.dismiss(id) | void | Dismiss a specific toast by the id returned from show/status methods. |
toast.dismissAll() | void | Dismiss every visible toast (useful on route change). |
toast.promise(promise, opts) | Promise | Shows a loading toast that swaps to success/error when the promise settles. opts: { loading, success, error } — each can be a string or function of the resolved/rejected value. |
Options
| Option | Type | Default | Notes |
|---|---|---|---|
title | string | — | The bold message. Required. |
description | string | — | Optional secondary line. |
status | "success" | "info" | "warning" | "danger" | "info" | Visual variant. |
duration | number (ms) | 4000 | Auto-dismiss after N ms. Pass 0 for persistent. |
action | { label, onClick } | — | Inline action button. Click runs onClick then dismisses. |
Inclusive by default
Accessibility
Toasts are tricky for accessibility — they appear without focus and disappear without warning. RenDS handles the announcement via live regions; you handle the message phrasing.
Live region behavior
- Success / info / warning use
aria-live="polite"— announced when the screen reader is idle. - Danger uses
aria-live="assertive"— interrupts the current announcement. Reserve for genuine errors.
Keyboard
Pause auto-dismiss on hover and focus. The viewport pauses the dismiss timer when the user hovers over it or any toast inside receives focus — they're trying to read it.
Patterns
Examples
Confirm a save
async function save() {
await api.save();
toast.success('Saved', { description: 'Visible to the team in a few seconds.' });
}
Undoable delete
function deleteRow(id) {
const backup = removeOptimistically(id);
toast.show({
title: 'Row deleted',
duration: 7000,
action: {
label: 'Undo',
onClick: () => restore(backup),
},
});
}
Persistent error with retry
toast.danger('Connection lost', {
description: 'Reconnecting…',
duration: 0, // sticks until dismissed
action: { label: 'Retry now', onClick: () => reconnect() },
});
Dismiss a toast programmatically
Status methods return an id. Store it and pass it to toast.dismiss when the underlying state changes.
// Show a persistent "uploading" toast, dismiss when done.
const uploadId = toast.info('Uploading…', { duration: 0 });
try {
await uploadFile(file);
toast.dismiss(uploadId);
toast.success('Upload complete');
} catch (err) {
toast.dismiss(uploadId);
toast.danger('Upload failed', { description: err.message });
}
Track an async operation with toast.promise
One call covers loading → success / error. The toast updates in place.
toast.promise(api.saveProfile(data), {
loading: 'Saving profile…',
success: 'Profile saved',
error: (err) => `Couldn't save: ${err.message}`,
});