molecule

Toast

Ephemeral notification that appears at a fixed screen position with semantic intents, auto-dismiss, stacking, and an optional close button. Consumers interact via ToastProvider + useToast() hook.

Overview

Toast notifications provide transient feedback after user actions. They appear at a configurable screen position, stack when multiple are shown, auto-dismiss after a configurable duration, and support four semantic intents: success, warning, danger, and info.

The API is context-based: wrap your app with <ToastProvider> and call useToast() in any descendant component to show toasts.

import { ToastProvider, useToast } from '@enara-health/ui-react';

// 1. Wrap your app
const App = () => (
  <ToastProvider position="bottom-right">
    <MyPage />
  </ToastProvider>
);

// 2. Use in any descendant
const MyPage = () => {
  const { toast } = useToast();

  return (
    <button onClick={() => toast({ message: 'Saved!', intent: 'success' })}>
      Save
    </button>
  );
};

Props

ToastProvider

PropTypeDefaultDescription
children ReactNode Required. Content to wrap with toast context
position 'top-left' | 'top-center' | 'top-right' | 'bottom-left' | 'bottom-center' | 'bottom-right' 'bottom-right' Screen position for the toast container
max number 5 Maximum number of visible toasts. Oldest evicted when exceeded.
defaultDuration number 5000 Default auto-dismiss duration in ms

ToastOptions (passed to toast())

PropTypeDefaultDescription
message string Required. The notification text
title string Optional heading displayed above the message
intent 'success' | 'warning' | 'danger' | 'info' 'info' Semantic intent controlling color and default icon
duration number 5000 Auto-dismiss delay in ms. 0 = persistent.
closable boolean true Whether the close button is shown
icon ReactNode Custom icon overriding the default intent icon
onDismiss () => void Callback fired when toast is removed

useToast() return value

MethodSignatureDescription
toast (options: ToastOptions) => string Show a toast. Returns the toast ID.
dismiss (id: string) => void Dismiss a specific toast
dismissAll () => void Dismiss all toasts

Intents

Each intent applies a distinct border color, background tint, and default icon:

const { toast } = useToast();

// Success — positive confirmation
toast({ message: 'Patient record saved', intent: 'success' });

// Warning — something needs attention
toast({ message: 'Session expires in 5 minutes', intent: 'warning' });

// Danger — error or failure
toast({ message: 'Failed to save changes', intent: 'danger' });

// Info — neutral informational (default)
toast({ message: 'New version available', intent: 'info' });

Positions

Configure the position via the ToastProvider. Click each button to see a toast appear at that position:

// Corner positions
<ToastProvider position="top-left">...</ToastProvider>
<ToastProvider position="top-right">...</ToastProvider>
<ToastProvider position="bottom-left">...</ToastProvider>
<ToastProvider position="bottom-right">...</ToastProvider>

// Center positions
<ToastProvider position="top-center">...</ToastProvider>
<ToastProvider position="bottom-center">...</ToastProvider>

Bottom positions use flex-direction: column-reverse so the newest toast appears closest to the screen edge.

Examples

With Title

// Success with title
toast({
  title: 'Success',
  message: 'Your changes have been saved.',
  intent: 'success',
});

// Error with title
toast({
  title: 'Error',
  message: 'Could not connect to server. Please try again.',
  intent: 'danger',
});

Persistent Toast

// duration: 0 keeps toast until manually dismissed
const id = toast({
  message: 'Uploading file... (persistent, no close button)',
  duration: 0,
  closable: false,
});

// 3 seconds later, auto-resolve:
dismiss(id);
toast({ message: 'Upload complete!', intent: 'success' });

With Callback

toast({
  message: 'Record deleted',
  intent: 'danger',
  onDismiss: () => toast({ message: 'onDismiss callback fired!', intent: 'info' }),
});

Custom Max Toasts

// Only show 3 toasts at a time — oldest evicted automatically
<ToastProvider max={3}>
  <App />
</ToastProvider>

Anti-Patterns

  • Using toast for confirmation dialogs — Toasts auto-dismiss and lack action buttons. Use Dialog for decisions that require user action.
  • Using toast for form validation errors — Validation errors should appear inline next to the relevant fields. Use FormField with the error prop.
  • Showing many toasts simultaneously — Stacking many toasts overwhelms users. Batch related notifications or use a notification center.
  • Using useToast() without ToastProvider — The hook will throw. Always wrap your app root with <ToastProvider>.

Accessibility

  • ARIA Live Region: Each toast uses role="alert" with aria-live="polite". Danger intents use aria-live="assertive" for immediate screen reader announcement.
  • Close Button: The close button has aria-label="Dismiss notification" and is focusable via keyboard.
  • Focus Ring: The close button displays a visible focus ring on keyboard navigation via :focus-visible.
  • Reduced Motion: Animations are disabled when prefers-reduced-motion: reduce is set.
  • WCAG Compliance: Meets AA standards.