Skip to content

Toaster

The page’s notification region. Render one, near the end of the body; every toast the page raises shows in it.

import { Toaster } from '@zitdevs/ui';

This page was rendered with a flash message in its toaster — “Request sent”, at the bottom of the window — as the page a form’s POST returns would be. The page’s script enhanced it on load: it is announced, and it leaves after five seconds unless the pointer or the focus is on it.

Request sent

A specialist will reply within one business day.

app/layout.tsx, in a React app
import { Toaster } from '@zitdevs/ui';
import { toasterLabels } from '@zitdevs/ui/labels/es';
<body>
{children}
<Toaster labels={toasterLabels.es} />
</body>;
An Astro page, with a flash message after a POST
---
import { Toast, Toaster } from '@zitdevs/ui';
const sent = Astro.url.searchParams.has('sent');
---
<Toaster>
{sent && <Toast tone="success" title="Request sent" description="We reply within a day." />}
</Toaster>
<script>
import { enhanceToaster } from '@zitdevs/ui/enhance';
enhanceToaster(document);
</script>

In React there is nothing to run: the toaster’s region is a small client part that enhances itself once it hydrates, and shows any toast() raised before then.

The toaster sits on the bottom edge. A page with a banner of its own fixed there, such as a cookie banner, lifts it with --toaster-offset, a token of @zitdevs/tokens (0px by default), so notifications never cover the banner:

:root:has(.cookie-banner) {
--toaster-offset: 88px;
}
Prop Type Default Notes
children ReactNode — The flash messages, as Toast elements. They show with no script.
duration number 5000 Milliseconds a toast stays when it does not say. Danger always stays.
limit number 3 Toasts shown at once; the oldest leaves first, an error last.
labels Partial<ToasterLabels> English { region, dismiss }. es.toaster from @zitdevs/ui/labels/es.
ref Ref<HTMLElement> — The region.
className string — On the region: a different z-*, say.
anything else <section> attributes — On the region.

Exported types: ToasterProps, ToasterLabels. From @zitdevs/ui/enhance: enhanceToaster, ToasterOptions ({ duration, limit }), ToasterEnhancement (show(), dismiss(id?), destroy()), and toast.

  • A <section> named “Notifications” (labels.region): a landmark a screen reader can jump to, to find a toast it heard about.
  • Two live regions, polite (role="status") and assertive (role="alert"), rendered empty from the first paint, with aria-atomic="false" so each toast is read on its own. A toast’s words are put in the one that matches its tone as it arrives, and taken out a little later; the visible toasts sit in their own list, outside the live regions, so nothing is announced twice.
  • A flash message the server rendered is announced too, once the toaster is enhanced and the page has settled.
  • Timers stop while the pointer is over the toasts, while focus is inside them, and while the page is hidden. Danger toasts stay until dismissed (WCAG 2.2.1).
  • When a focused toast goes, focus moves to the next toast, or back to where it came from, or to the region itself — never to the top of the page.
  • The region spans the bottom edge without catching a click: only its toasts take the pointer.
  • While a modal Dialog is open, the browser makes the rest of the page inert, the toaster included: raise the toast once the dialog has closed, or say it inside the dialog.

The region, its live regions and the flash messages it was given are server HTML: the messages show, and stay. The dismiss buttons wait out of sight until the enhancer runs, since they would do nothing before. enhanceToaster(document) — or React’s hydration — then times, announces and dismisses them, and takes every toast().

The toasts’ roles (see Toast); --toaster-offset for its distance from the bottom edge; z-70, above the page’s own layers, overridable with className.