# How to Use the Astryx Toast Notification System with the useToast Hook

> Learn to use the Astryx Toast notification system with the useToast hook. Effortlessly manage toasts with automatic viewport attachment, stacking, and timers for a seamless user experience.

- Repository: [Meta/astryx](https://github.com/facebook/astryx)
- Tags: how-to-guide
- Published: 2026-08-06

---

**The Astryx `useToast` hook returns an imperative `showToast` function that automatically manages viewport attachment, stacking, auto-dismiss timers, and deduplication, falling back to a singleton detached DOM tree if no `ToastViewport` provider exists.**

The Astryx design system (facebook/astryx) provides a robust notification layer built around a hook-driven API. The **Toast notification system** abstracts away positioning, lifecycle management, and accessibility concerns through a single `useToast` hook. This article breaks down the implementation details found in the core source code and demonstrates how to trigger, customize, and manage toast notifications in React applications.

## Core Hook API and Fallback Viewport

The `useToast` hook (located in [`packages/core/src/Toast/useToast.tsx`](https://github.com/facebook/astryx/blob/main/packages/core/src/Toast/useToast.tsx)) exports an imperative interface that bypasses the need for manual context wiring. When invoked, the hook obtains a `ToastContext` from the nearest `ToastViewport` provider. If no provider is present in the component tree, the hook lazily creates a **singleton fallback viewport** (a detached DOM tree) via `getFallbackContext()`—this singleton is created only once per application instance (lines 61-79).

The hook returns a `showToast` function of type `ShowToastFn`. Calling this function generates a unique toast ID using `generateToastId`, constructs a toast entry object, and dispatches it to the context via `ctx.addToast(entry)`. The function also returns a dismissal callback that invokes `ctx.removeToast(id, 'manual')` to programmatically dismiss the notification.

## Viewport Context and Stacking Logic

The `ToastViewport` component ([`packages/core/src/Toast/ToastViewport.tsx`](https://github.com/facebook/astryx/blob/main/packages/core/src/Toast/ToastViewport.tsx)) supplies the `ToastContext` that stores the list of active toasts and provides utility methods such as `findByUniqueID`. This component handles the actual rendering of each toast inside a `<Toast>` component, applying enter/exit animations and managing **stacking order** for multiple simultaneous notifications.

The viewport also manages **focus handling** and **ARIA live region announcements** through the `useAnnounce` hook. When the viewport operates in fallback mode (detached from the main React tree), it mirrors the page's theme attributes—`data-theme` and `data-astryx-theme`—via `syncRootThemeAttrs` to ensure CSS `@scope` rules apply correctly to the toast notifications.

## Deduplication and Collision Behavior

Each toast entry supports a `uniqueID` option that enables intelligent **deduplication**. When a toast with a matching `uniqueID` is already active, the `collisionBehavior` option (defined in [`packages/core/src/Toast/types.ts`](https://github.com/facebook/astryx/blob/main/packages/core/src/Toast/types.ts)) determines whether the existing toast is overwritten or the new request is ignored. This prevents notification spam when users trigger the same action repeatedly.

The entry object also contains lifecycle options including `isAutoHide` (boolean), `duration` (milliseconds), and callbacks such as `onHide`. When `isAutoHide` is true, the viewport automatically initiates removal after the specified duration, invoking the exit animation before calling `ctx.removeToast`.

## Implementation Examples

Simple success notification:

```tsx
import { Button } from '@astryxdesign/core';
import { useToast } from '@astryxdesign/core/Toast';

function SaveButton() {
  const toast = useToast();

  const handleSave = async () => {
    try {
      await saveData();
      toast({ body: 'Saved successfully' });
    } catch {
      toast({ body: 'Failed to save', type: 'error' });
    }
  };

  return <Button label="Save" onClick={handleSave} />;
}

```

Toast with action and deduplication:

```tsx
import { useToast } from '@astryxdesign/core/Toast';
import { Button } from '@astryxdesign/core';

function DeleteItem({ itemId }) {
  const toast = useToast();

  const handleDelete = () => {
    deleteItem(itemId);
    toast({
      body: 'Item deleted',
      endContent: <Button label="Undo" onClick={() => restoreItem(itemId)} />,
      uniqueID: `delete-${itemId}`, // Prevents duplicate notifications
    });
  };

  return <Button label="Delete" onClick={handleDelete} />;
}

```

Explicit viewport placement (optional):

```tsx
import { ToastViewport } from '@astryxdesign/core/Toast';

function App() {
  return (
    <>
      {/* Application content */}
      <ToastViewport position="bottomEnd" maxVisible={5} />
    </>
  );
}

```

## Summary

- The `useToast` hook in [`packages/core/src/Toast/useToast.tsx`](https://github.com/facebook/astryx/blob/main/packages/core/src/Toast/useToast.tsx) provides an imperative API that automatically handles viewport attachment and fallback creation.
- **Fallback viewport** logic ensures toast functionality works even without an explicit `ToastViewport` provider, creating a singleton detached DOM tree on first use.
- Deduplication is controlled via `uniqueID` and `collisionBehavior` properties in the toast entry object.
- The `ToastViewport` component manages stacking, animations, auto-hide timers, focus handling, and screen reader announcements via ARIA live regions.
- Theme attributes are automatically synchronized to the fallback viewport using `syncRootThemeAttrs` to maintain styling consistency.

## Frequently Asked Questions

### How does the useToast hook handle cases where no ToastViewport is rendered?

The hook implements a lazy fallback mechanism via `getFallbackContext()`. When no provider is found in the component tree, it creates a singleton detached DOM tree that acts as a viewport. This fallback is created only once per application lifecycle and automatically mirrors theme attributes from the document root.

### What is the purpose of the uniqueID option when calling the toast function?

The `uniqueID` string enables deduplication logic. When a toast with an identical `uniqueID` is already active, the system consults the `collisionBehavior` option to either overwrite the existing toast or ignore the duplicate request. This prevents notification spam from rapid user interactions.

### Can I programmatically dismiss a toast before its auto-hide timer expires?

Yes. The `showToast` function returns a dismiss callback that invokes `ctx.removeToast(id, 'manual')`. Store this callback from the toast invocation and call it to immediately trigger the exit animation and remove the notification from the stack.

### Where are the type definitions for toast configuration options located?

The TypeScript interfaces for toast options, entries, and dismiss reasons are defined in [`packages/core/src/Toast/types.ts`](https://github.com/facebook/astryx/blob/main/packages/core/src/Toast/types.ts). This includes the `ShowToastFn` type signature and the `collisionBehavior` enum for handling duplicate notifications.