Toast
Confirms that something happened, without interrupting what the user is doing.
When to Use
Use when:
An action succeeded or failed and the user doesn't need to do anything about it — saved, copied, deleted. Toasts confirm; they don't ask.
Variants
Four severities, each with its own icon. Every one is created from JavaScript — there is no PHP call that renders a toast.
wsToastSuccess('Changes saved.');
wsToastError('Something went wrong');
wsToastWarning('Please review');
wsToastInfo('New updates');States
With an action
One action, typically Undo. Keep the window generous — the default four seconds is short for anyone navigating by keyboard.
wsToast('Item deleted', 'info', {
duration: 10000, // give people time to reach it
action: { label: 'Undo', onClick: () => restoreItem(id) },
});Duration
Four seconds by default. Longer for anything actionable, longer still for errors the user may want to read twice.
wsToastInfo('Quick toast', { duration: 2000 });
wsToastInfo('Long toast', { duration: 8000 });| State | Behavior |
|---|---|
| Appearing | The toast is created and appended to #ws-toast-container, which is fixed-position and always in the DOM. |
| Visible | Persists for duration milliseconds — 4000 by default. |
| Dismissing | Removed automatically on timeout, or immediately via the close button. There's no hover-to-pause, so a toast can expire while it's being read. |
| Closable | On by default. Pass closable: false to omit the button — only sensible for very short, purely informational toasts. |
| Stacking | Multiple toasts stack in the container. Nothing caps the number, so guard against loops that could fire dozens. |
Real-World Usage
The save-and-confirm pattern used across the Planner: success on the happy path, error with a longer duration on failure, and no toast at all when the user can already see the result.
async function savePlan(plan) {
try {
const res = await fetch('/api/plans.php', { method: 'POST', body: JSON.stringify(plan) });
const data = await res.json();
if (!data.success) throw new Error(data.message);
wsToastSuccess('Workshop saved');
} catch (err) {
// Errors get longer on screen than confirmations.
wsToastError('Could not save — ' + err.message, { duration: 8000 });
}
}Options
PHP setup
Render the container once per page, usually in the footer. Without it, every wsToast() call silently does nothing.
<?= ws_toast_container() ?>
JavaScript API
| Function | Purpose |
|---|---|
wsToast(message, variant, options) | Full control |
wsToastSuccess(message, options) | Success shorthand |
wsToastError(message, options) | Error shorthand |
wsToastWarning(message, options) | Warning shorthand |
wsToastInfo(message, options) | Info shorthand |
Options object
| Option | Type | Default | Purpose |
|---|---|---|---|
message | string | — | First argument. One short sentence, no full stop needed. |
variant | string | 'info' | success | error | warning | info |
duration | number | 4000 | Milliseconds before auto-dismiss. Falsy values fall back to the default, so 0 will not make a toast persist. |
closable | bool | true | Show the close button. Only an explicit false removes it. |
action.label | string | null | Action button text |
action.onClick | function | null | Action click handler |
Accessibility
| Concern | Behavior |
|---|---|
| Live region | The container is aria-live="polite", so new toasts are announced once the screen reader finishes its current sentence — the right choice for confirmations, which shouldn't interrupt. Each toast carries its own aria-atomic="true", so only the new one is read, not the whole stack. |
| Keyboard | The close and action buttons are real buttons, reachable with Tab. Because the container is at the end of the document, reaching them may take many presses from where the user was. |
| Colour independence | Variant colour and icon are the only difference between success and error. Put the outcome in the words — "Workshop saved", not "Done". |
| Contrast | All variants render on the dark --toast-bg with --toast-text, a single tested pairing. |
warning
Two limitations worth knowing:
(1) Auto-dismiss conflicts with WCAG 2.2.1 (Timing Adjustable). Content disappears on a timer with no way to pause or extend it, and there's no hover-to-pause. Keep anything that matters out of a toast, and give actionable toasts a long duration.
(2) Error toasts are announced politely. A failure may be missed if the screen reader is mid-sentence. For errors that block the user's goal, put an Alert on the page as well.
(1) Auto-dismiss conflicts with WCAG 2.2.1 (Timing Adjustable). Content disappears on a timer with no way to pause or extend it, and there's no hover-to-pause. Keep anything that matters out of a toast, and give actionable toasts a long duration.
(2) Error toasts are announced politely. A failure may be missed if the screen reader is mid-sentence. For errors that block the user's goal, put an Alert on the page as well.
Tokens
| Token | Used for |
|---|---|
--toast-bg / --toast-text | Toast surface and message colour |
--toast-radius / --toast-shadow | Corners and elevation above the page |
--text-inverse | Text on the dark surface |
--mainsite-light | Action button accent |
--gray-400 | Close button, resting |
--radius-md | Action and close button corners |
--space-3 | Internal spacing and the gap between stacked toasts |
--text-caption / --text-meta | Message and action type scale |
--font-body / --font-medium / --font-semibold | Face and weights |
--transition-fast | Button hover |
CSS Classes
| Class | Purpose |
|---|---|
.ws-toast-container | Fixed container, id="ws-toast-container" — the node the JS appends into |
.ws-toast | Individual toast |
.ws-toast--success / --error / --warning / --info | Variant colours |
.ws-toast__icon | Variant icon |
.ws-toast__message | Message text |
.ws-toast__action | Optional action button |
.ws-toast__close | Dismiss button |
Files
| File | Purpose |
|---|---|
includes/components/helpers.php | ws_toast_container() helper function |
includes/components/toast.php | The container element and its live-region attributes |
includes/components/components.css | Styles (.ws-toast rules) |
includes/components/components.js | wsToast() and the four shorthands |