Notifications
Mount one toaster, then dispatch notifications from React components or ordinary modules.
<CratisComponentsProvider toaster> <Application /></CratisComponentsProvider>import { toast } from '@cratis/components/Notifications';
toast.success({ title: 'Saved', description: 'Your changes were saved.',});Imperative API
Section titled “Imperative API”toast(options)toast.success(options)toast.info(options)toast.warn(options)toast.error(options)toast.secondary(options)toast.contrast(options)toast.update(id, updates)toast.dismiss(id?)toast.promise(promise, states)
The queue is shared across loaded Components copies. setToastDispatch() installs an application-owned dispatch and returns a scoped restore callback.
Building a custom rendering surface
Section titled “Building a custom rendering surface”The default Toaster is optional. An application that wants full control over how
notifications render — a different animation library, a non-portal placement, or
integration with an existing app-wide notification center — can build its own surface
on the same primitives Toaster itself uses:
subscribeToToasts(listener)subscribes to the shared queue and returns an unsubscribe callback. Call it inside auseSyncExternalStore/useEffectbinding.getToastSnapshot()returns the current, immutable array of queuedToastRecordvalues — the snapshot to read whenever the subscription notifies of a change.ToastRecordisToastOptions & { id: ToastId }, the exact shape stored in the queue; render each record’stitle/description/render, honordismissible, and call the imperativetoastAPI (or a customToastDispatch) to dismiss it.ToastDispatchis the interface implemented by whateversetToastDispatch()installs — implement it to redirect everytoast(...)call to a different in-app system (or to a test double) instead of the built-in queue.
A minimal custom subscriber:
import { useSyncExternalStore } from 'react';import { subscribeToToasts, getToastSnapshot } from '@cratis/components/Notifications';
const CustomToastRegion = () => { const toasts = useSyncExternalStore(subscribeToToasts, getToastSnapshot); return ( <div role='region' aria-label='Notifications'> {toasts.map((toast) => ( <CustomToastFrame key={toast.id} toast={toast} /> ))} </div> );};Accessible behavior
Section titled “Accessible behavior”- Error frames use
role="alert"; other frames userole="status". - The notification region is labeled and polite.
- Every dismissible frame retains a localized close control, including custom bodies.
- Auto-dismiss pauses while the frame is hovered or contains keyboard focus.
- Timeouts have a five-second accessibility floor.
Custom body
Section titled “Custom body”toast.error({ render: <FailureDetails />, dismissible: true,});Custom content replaces only the body. The frame, severity indicator, timeout, and dismiss control remain owned by Components.
Toaster props
Section titled “Toaster props”| Prop | Purpose |
|---|---|
position | One of the six viewport edges/corners. |
limit | Maximum visible frames. |
timeout | Default timeout in milliseconds. |
dismissAriaLabel | Accessible name for close controls. Falls back to the CratisComponentsProvider’s messages.notifications.dismiss, then 'Dismiss'. |
regionAriaLabel | Accessible name for the notification region. Falls back to the provider’s messages.notifications.region, then 'Notifications'. |
pt | Stable region, toast, icon, content, title, description, action, and close parts. |
Configure dismissAriaLabel / regionAriaLabel once for the whole application through
CratisComponentsProvider’s messages.notifications, or override either per <Toaster> instance.