Skip to content
Components, switch product

Toast

A toast is a short message about something that just happened, such as “Draft saved”, that doesn’t interrupt the user. toast() shows one, from any framework or from plain JavaScript, and <gui-toaster> is where the toasts appear: an empty element you put in the page once.

Code of the example above
ToastBasic.tsx
import { GuiButton, GuiToaster } from '@golemui/gui-components/react';
import { toast } from '@golemui/gui-components/toast';
import '@golemui/gui-components/index.css';
export function ToastBasic() {
return (
<>
<GuiButton
id="save-draft-button"
label="Save draft"
variant="outlined"
onClick={() => toast({ message: 'Draft saved.', variant: 'success' })}
/>
<GuiToaster />
</>
);
}

The demos on this page import toast() from a CDN, since a snippet in the browser can’t import a package by name. In your app, import it from the package as the comment shows.

The entry point is @golemui/gui-components/toast, which exports toast() and registers <gui-toaster>. To install the package and load the stylesheet, see Installation.

Render one <gui-toaster> in the page, usually at the end of your app’s layout, then call toast() from anywhere:

index.html
<gui-toaster></gui-toaster>
main.ts
import { toast } from '@golemui/gui-components/toast';
import '@golemui/gui-components/index.css';
toast({ message: 'Draft saved.', variant: 'success' });

Render the toaster up front, not when the first toast comes: screen readers only announce what changes in a live region that is already in the page. A toast sent before the toaster connects waits for it, and on the server toast() does nothing, so you can call it from code that also runs there.

In React, render <GuiToaster /> once. In Angular, Vue and Lit, render <gui-toaster> in your root template. Each example below shows all four.

toast() takes an object, and returns a handle with the toast’s id and a dismiss() method that closes it, or takes it out of the queue.

OptionTypeWhat it does
messagestringThe text of the toast. Required.
titlestringA short heading above the message.
variant'default' | 'info' | 'success' | 'warning' | 'error'The intent it shows, as on gui-alert. An error is announced at once.
durationnumberMilliseconds on screen, 5000 by default. Infinity keeps it until the user closes it, the default for an error and for a toast with an action.
action{ label: string; onAction: () => void }A button in the toast that runs onAction, then closes it.
idstringNames the toast. A toast with the id of one on screen replaces it.
toasterstringThe id of the gui-toaster to show it in. Defaults to the first one in the page.
onDismiss(reason) => voidRuns when the toast closes, with why: 'timeout', 'close', 'escape', 'action' or 'api' (its dismiss()).

The types are exported too: GuiToastOptions, GuiToastVariant, GuiToastHandle and GuiDismissReason.

The API of <gui-toaster>:

Properties

Property Type Default Description
placement GuiToasterPlacement 'bottom-end' Where the toasts stack.
max number 3 How many toasts show at once; the rest wait.
regionLabel attribute region-label string – The region's accessible name. Defaults to "Notifications".
dismissLabel attribute dismiss-label string – The close buttons' accessible name. Defaults to "Dismiss notification".

Methods

Method Description
show(id: string, options: GuiToastOptions): void Shows a toast, or queues it when the toaster is full. A toast with the id of one already here replaces it. toast calls it.
dismiss(id: string, reason: GuiDismissReason): Closes a toast, or drops it from the queue, and fires gui-dismiss.

Events

Every event bubbles and is composed, so you can listen on any ancestor.

Event Description
gui-dismiss A toast closed. detail.id is its id and detail.reason why it closed.
gui-action The user pressed a toast's action. detail.value is the toast's id and detail.item the toast.

variant gives the toast the color of an intent, as on gui-alert, over an opaque background, since it floats above the page. title adds a heading above the message.

Code of the example above
ToastVariants.tsx
import { GuiButton, GuiToaster } from '@golemui/gui-components/react';
import {
toast,
type GuiToastOptions,
type GuiToastVariant,
} from '@golemui/gui-components/toast';
import '@golemui/gui-components/index.css';
const toasts: Record<GuiToastVariant, Omit<GuiToastOptions, 'variant'>> = {
default: { message: 'Your changes are saved as you type.' },
info: { title: 'New version', message: 'Reload to get the latest features.' },
success: { title: 'Invite sent', message: 'Grace will get an email shortly.' },
warning: { title: 'Almost full', message: 'You have used 90% of your storage.' },
error: { title: 'Could not save', message: 'Check your connection and try again.' },
};
const labels: Record<GuiToastVariant, string> = {
default: 'Default',
info: 'Info',
success: 'Success',
warning: 'Warning',
error: 'Error',
};
export function ToastVariants() {
return (
<>
<div className="gui-grid gui-grid--row gui-grid--justify-start">
{(Object.keys(toasts) as GuiToastVariant[]).map((variant) => (
<div key={variant} className="gui-grid__cell">
<GuiButton
id={`toast-${variant}`}
label={labels[variant]}
variant="outlined"
onClick={() => toast({ ...toasts[variant], variant })}
/>
</div>
))}
</div>
<GuiToaster />
</>
);
}

action adds a button to the toast, such as Undo. It runs onAction, then closes the toast. A toast with an action stays until the user closes it, so the user has time to reach the button. Keep the action available elsewhere too: a toast goes away, and a screen reader user may hear it after they moved on.

The card is on the board.

Code of the example above
ToastAction.tsx
import { useState } from 'react';
import { GuiButton, GuiToaster } from '@golemui/gui-components/react';
import { toast } from '@golemui/gui-components/toast';
import '@golemui/gui-components/index.css';
export function ToastAction() {
const [archived, setArchived] = useState(false);
const archive = () => {
setArchived(true);
toast({
message: 'Card archived.',
action: { label: 'Undo', onAction: () => setArchived(false) },
});
};
return (
<>
<GuiButton
id="archive-card"
label="Archive card"
variant="outlined"
onClick={archive}
/>
<p id="card-status" role="status">
{archived ? 'The card is archived.' : 'The card is on the board.'}
</p>
<GuiToaster />
</>
);
}

A toast with the id of one on screen replaces it, with a fresh time on screen. Use it for a task that ends later, such as an upload: show a toast that stays, then replace it with the result. The handle’s dismiss() closes a toast from your code.

Code of the example above
ToastUpdate.tsx
import { GuiButton, GuiToaster } from '@golemui/gui-components/react';
import { toast } from '@golemui/gui-components/toast';
import '@golemui/gui-components/index.css';
function upload() {
// One id: the second toast replaces the first one.
toast({ id: 'report-upload', message: 'Uploading report.pdf…', duration: Infinity });
// Stands in for the upload.
setTimeout(() => {
toast({ id: 'report-upload', message: 'report.pdf uploaded.', variant: 'success' });
}, 2000);
}
export function ToastUpdate() {
return (
<>
<GuiButton
id="upload-report"
label="Upload report"
variant="outlined"
onClick={upload}
/>
<GuiToaster />
</>
);
}

placement on the toaster sets where the toasts stack: a corner, top-start, top-end, bottom-start or bottom-end, the default, or the middle of the top or bottom edge, top or bottom. The newest toast is next to that edge. max is how many show at once, 3 by default: the rest wait in a queue, and each one shows when another closes.

A page can have more than one toaster. Give a toaster an id, and pass it to toast() as toaster.

Code of the example above
ToastPlacement.tsx
import { useRef } from 'react';
import { GuiButton, GuiToaster } from '@golemui/gui-components/react';
import { toast } from '@golemui/gui-components/toast';
import '@golemui/gui-components/index.css';
export function ToastPlacement() {
const count = useRef(0);
const notify = () => {
count.current += 1;
toast({ toaster: 'top-toaster', message: `Notification ${count.current}` });
};
return (
<>
<GuiButton
id="notify-top"
label="Show at the top"
variant="outlined"
onClick={notify}
/>
<GuiToaster id="top-toaster" placement="top" max={2} />
</>
);
}

A toast closes on its own after its duration. Its time pauses while the pointer is over the toasts, while the focus is in them, and while the browser tab is hidden, so the user doesn’t miss a toast they are reading or reaching for. The user can close a toast at any time with its close button, or with Escape while the focus is in it.

While a gui-dialog is open, the rest of the page is inert, and so would be the toasts. The toaster moves its toasts inside the open dialog until it closes, so the user can still read them and use their buttons. A <dialog> you open with showModal() yourself, outside a gui-dialog, hides them.

<gui-toaster> fires gui-dismiss when a toast closes, with its id and the reason in event.detail, and gui-action when the user presses a toast’s action, with the toast’s id in event.detail.value. They suit code that watches every toast, such as analytics: for one toast, onDismiss and onAction are simpler.

<gui-toaster> renders its toasts in a region it shows in the top layer while it has toasts. Each toast has a body, the action when it has one, and a close button. Two visually hidden live regions after the list announce the toasts:

gui-toaster
<gui-toaster placement="bottom-end">
<section
class="gui-toaster__region"
popover="manual"
aria-label="Notifications"
data-placement="bottom-end"
>
<ol class="gui-toaster__list">
<li class="gui-toast" data-id="gui-toast-1" data-variant="success">
<div class="gui-toast__body">
<p class="gui-toast__title">Invite sent</p>
<p class="gui-toast__message">Grace will get an email shortly.</p>
</div>
<button type="button" class="gui-toast__action">Undo</button>
<button
type="button"
class="gui-toast__close"
aria-label="Dismiss notification"
>
<svg aria-hidden="true">…</svg>
</button>
</li>
</ol>
<div class="gui-visually-hidden" role="status" aria-atomic="false"></div>
<div class="gui-visually-hidden" role="alert" aria-atomic="false"></div>
</section>
</gui-toaster>
ClassPart
gui-toaster__regionThe region, fixed to the edge data-placement names. It moves into an open gui-dialog.
gui-toaster__listThe list of the toasts on screen.
gui-toastOne toast. data-variant names its intent, and data-leaving is set while it fades out.
gui-toast__bodyThe title and the message.
gui-toast__titleThe title, when the toast has one.
gui-toast__messageThe message.
gui-toast__actionThe action button, when the toast has one.
gui-toast__closeThe close button.

The region can move into a dialog, away from gui-toaster, so select its parts by class, not as descendants of gui-toaster:

styles.css
/* Square toasts with a stronger title. */
.gui-toast {
border-radius: 0;
}
.gui-toast__title {
font-weight: 700;
}

The toasts read these design tokens. Set them on :root to change every toast:

TokenWhat it styles
--gui-toast-widthThe width of the toasts, 22rem by default, never more than the viewport.
--gui-bg-defaultThe background of a default toast.
--gui-border-defaultThe border of a default toast.
--gui-text-defaultThe text of a default toast.
--gui-intent-*-surfaceThe background of a toast of that intent: info, success, warning or error.
--gui-intent-*The border of a toast of that intent.
--gui-intent-*-textThe text of a toast of that intent.
--gui-radius-mdThe corner radius of a toast.
--gui-radius-smThe corner radius of the buttons.
--gui-shadow-lgThe shadow of a toast.
--gui-shadow-focusThe focus ring of the buttons.
--gui-font-familyThe font.
--gui-font-smThe text size.
--gui-space-2The space between the toasts, and the padding of the action.
--gui-space-3The padding of a toast, and the space between its parts.
--gui-space-4The space from the edge of the viewport, and the slide of a new toast.
--gui-overlay-durationHow long a toast takes to fade and slide in, and to fade out. Reduced motion skips it.

To restyle beyond the tokens, see Overriding styles; for dark mode and the Clay theme, see Themes and dark mode.

  • Announcements. Screen readers read each toast when it shows: its title, then its message. A toast of any variant but error waits until the user is idle, through a status live region. An error interrupts, through an alert region.
  • Region. The toasts are in a region named “Notifications”, which users can reach from a screen reader’s list of landmarks. Rename it with region-label, or translate it under the key notifications.
  • Close button. Each toast has a close button named “Dismiss notification”. Rename it with dismiss-label, or translate it under the key dismissNotification.
  • Focus. A toast never takes the focus. When a toast closes while the focus is in it, the focus moves to the next toast, or back to where it was before it entered the toasts.
  • Time. A toast’s time pauses while the user points at it or is in it, and a toast with an action or an error stays until the user closes it. Don’t use a toast for something the user must answer: use a dialog.
KeyAction
TabMoves through the buttons of the toasts.
Enter SpacePresses the action or the close button.
EscapeIn a toast: closes it.

What every element shares, such as translating the messages, is in Accessibility.