The toast system provides global, non-modal notifications for transient events like success confirmations or errors. It is composed of a ToastProvider, a useToast hook for triggering notifications, and several internal components that handle rendering and accessibility.
The provider is located at src/components/toast/toast-provider.tsx.
The ToastProvider is a context provider that must be mounted near the root of the application tree, inside the <PreferencesProvider>. It manages the state of all toasts and renders the ToastViewport (the visible list of toasts) and ToastAnnouncer (for screen reader announcements).
Props
| Prop | Type | Required | Description |
|---|---|---|---|
children |
React.ReactNode |
Yes | The rest of the application that needs access to the toast system. |
Usage
In src/app/layout.tsx, wrap your main content:
<PreferencesProvider>
<ToastProvider>
<App />
</ToastProvider>
</PreferencesProvider>The useToast hook provides access to the toast context from any client component rendered inside ToastProvider.
Return Value
It returns an object with the following properties:
| Method | Type | Description |
|---|---|---|
showSuccess(toast) |
(toast: ToastInput) => string |
Displays a success toast. Returns a unique ID, or 'suppressed' in Quiet Mode. |
showError(toast) |
(toast: ToastInput) => string |
Displays an error toast. Returns a unique ID. |
dismissToast(id) |
(id: string) => void |
Manually dismisses a toast by its ID. |
toasts |
ToastRecord[] |
An array of the currently visible toast objects. |
ToastInput Type
The showSuccess and showError methods accept an object with the following shape:
| Prop | Type | Required | Description |
|---|---|---|---|
title |
string |
Yes | The main heading for the toast. |
description |
string |
No | Additional explanatory text. |
duration |
number |
No | Auto-dismiss delay in milliseconds. Overrides the user's preference. |
action |
ToastAction |
No | An optional action button. See ToastAction below. |
ToastAction Type
| Prop | Type | Required | Description |
|---|---|---|---|
label |
string |
Yes | The text label for the action button. |
onClick |
() => void |
Yes | Callback fired when the button is clicked. The toast is dismissed immediately after. |
When the user preference quietMode is true, showSuccess() calls are suppressed. The function returns the string 'suppressed' and no toast is shown. This allows users to opt out of non-critical notifications.
showError() calls are not affected by Quiet Mode and will always display a toast.
The auto-dismiss duration for a toast is determined in the following order of precedence:
-
Per-call
duration: Aduration(in milliseconds) passed directly in theToastInputobject always takes priority. -
User Preference: If no per-call duration is provided, the system uses the
toastDurationvalue fromusePreferences():Preference Duration 'short'2500 ms 'normal'5000 ms 'long'10000 ms 'persistent'No auto-dismiss
The vertical spacing between stacked toasts is controlled by the user's toastDensity preference:
'relaxed'(default):gap-3(12px)'compact':gap-1.5(6px)
To prevent the UI from being overwhelmed, a maximum of 4 toasts can be visible at once. If a fifth toast is created, the oldest (top-most) toast is automatically dismissed to make room.
Auto-dismiss timers are automatically paused when a toast is hovered with the mouse or receives keyboard focus. The timer resumes when the interaction ends.
The toast system is designed to be accessible to screen reader users through several mechanisms.
The visible container for toasts has role="region" and an aria-label="Notifications". Individual toasts have roles based on their variant:
- Success Toasts:
role="status"for polite announcements. - Error Toasts:
role="alert"for assertive, immediate announcements.
In addition to the roles on the toasts themselves, ToastProvider renders a ToastAnnouncer component. This component contains two visually hidden aria-live regions to ensure announcements are handled correctly and consistently across screen readers:
aria-live="polite": Announces the title and description of the most recent success toast. This does not interrupt the user.aria-live="assertive": Announces the title and description of the most recent error toast. This will interrupt the user to deliver the time-sensitive message.
This dual-region approach provides a robust fallback for assistive technologies that may handle role="alert" and role="status" on dynamic elements inconsistently.
'use client';
import { useToast } from '@/components/toast/toast-provider';
import { Button } from '@/components/ui/button';
function MyComponent() {
const { showSuccess, showError } = useToast();
const handleSuccess = () => {
showSuccess({
title: 'Profile Updated',
description: 'Your changes have been saved successfully.',
});
};
const handleError = () => {
showError({
title: 'Connection Lost',
description: 'Please check your network and try again.',
action: {
label: 'Retry',
onClick: () => console.log('Retrying...'),
},
});
};
return (
<div className="flex gap-2">
<Button onClick={handleSuccess}>Show Success</Button>
<Button variant="destructive" onClick={handleError}>
Show Error
</Button>
</div>
);
}