# Toast (/docs/toast)





## API Reference [#api-reference]

<BaseUIReference href="https://base-ui.com/react/components/toast" />

## Basic [#basic]

Mount one `ToastProvider` near the application root. Any component inside it can call
`useToastManager()` for stacked toasts or `useAnchoredToastManager()` for anchored toasts.
`ToastRegion` and `ToastAnchoredRegion` render their portals and viewports automatically; use
`classNames.portal` and `classNames.viewport` only when those infrastructure slots need custom
styling.

<Preview cssProperties="toastPlaygroundCssProperties">
  <ToastExample />

  <Preview.Code>
    {`
          import {
            Button,
            ToastProvider,
            ToastRegion,
            useToastManager,
          } from "moduix";

          export function App() {
            return (
              <ToastProvider>
                <AppShell />
                <ToastRegion />
              </ToastProvider>
            );
          }

          function AppShell() {
            const toastManager = useToastManager();

            function showToast() {
              toastManager.add({
                title: "Saved",
                description: "Changes were saved successfully.",
              });
            }

            return <Button onClick={showToast}>Save changes</Button>;
          }
        `}
  </Preview.Code>

  <Preview.CSSProperties>
    {(context) => <ToastCssPropertiesPanel {...context} />}
  </Preview.CSSProperties>

  <Preview.CSSPlayground>
    {(context) => <ToastCssPlaygroundPanel {...context} />}
  </Preview.CSSPlayground>
</Preview>

## Anatomy [#anatomy]

`ToastProvider` owns the toast managers. `ToastRegion` renders stacked notifications and
`ToastAnchoredRegion` renders contextual notifications tied to an anchor element. Both regions
create their `Portal`, `Viewport`, and anchored `Positioner` service slots automatically, so the
public composition stays focused on visible toast content.

```text
ToastProvider
├─ app content
├─ ToastRegion
│  └─ ToastRoot
│     └─ ToastContent
│        ├─ ToastTitle
│        ├─ ToastDescription
│        ├─ ToastAction
│        └─ ToastClose
└─ ToastAnchoredRegion
   └─ anchored toast
```

```tsx
<ToastProvider>
  <AppShell />
  <ToastRegion placement="bottom-right" />
  <ToastAnchoredRegion />
</ToastProvider>
```

| Part                  | Role                                                                                                 |
| --------------------- | ---------------------------------------------------------------------------------------------------- |
| `ToastProvider`       | Provides the stacked and anchored toast managers to the subtree.                                     |
| `ToastRegion`         | Renders the shared portal and viewport for stacked toasts. Use `placement` and `stackBehavior` here. |
| `ToastRoot`           | Visible notification surface. Use it inside `renderToast` when a custom toast layout is needed.      |
| `ToastContent`        | Content wrapper for title, description, actions, icons, and custom layout.                           |
| `ToastTitle`          | Renders the toast title from the toast object.                                                       |
| `ToastDescription`    | Renders the toast description from the toast object.                                                 |
| `ToastAction`         | Optional action button rendered from `actionProps` in the default composition.                       |
| `ToastClose`          | Dismiss button with the default close icon, or custom children.                                      |
| `ToastAnchoredRegion` | Renders anchored feedback near the element passed to `useAnchoredToastManager().show({ anchor })`.   |

The service slots are still customizable when needed: pass `container` to choose the portal target
and `classNames.portal`, `classNames.viewport`, or `classNames.positioner` to style infrastructure.
For ordinary visual changes, prefer `className` on `ToastRegion` or a custom `renderToast`
composition.

## Composition [#composition]

Mount one `ToastProvider` near the application root, place `ToastRegion` once per stacked viewport,
and call `useToastManager()` from descendants to enqueue notifications. `ToastRegion` owns
placement, stack behavior, and the default toast markup, so applications do not need to compose
`Portal` or `Viewport` manually.

Use `renderToast` when the default markup is not enough. The callback receives the Base UI toast
object and should return a complete visible composition with `ToastRoot` and the parts your layout
needs. Anchored feedback uses the same provider, but goes through `useAnchoredToastManager()` and
`ToastAnchoredRegion` so contextual toasts do not mix with the stacked notification queue.

## Examples [#examples]

### Action [#action]

Use `actionProps` for a compact action button inside the default toast composition.

<Preview>
  <ActionToastExample />

  <Preview.Code>
    {`
          import { ToastProvider, ToastRegion, useToastManager, Button } from "moduix";

          export function App() {
            return (
              <ToastProvider>
                <UploadButton />
                <ToastRegion />
              </ToastProvider>
            );
          }

          function UploadButton() {
            const toastManager = useToastManager();

            return (
              <Button
                onClick={() =>
                  toastManager.add({
                    title: "File uploaded",
                    description: "The file is ready to share.",
                    actionProps: {
                      children: "Undo",
                      onClick: () => toastManager.add({ description: "Upload reverted." }),
                    },
                  })
                }
              >
                Create action toast
              </Button>
            );
          }
        `}
  </Preview.Code>
</Preview>

### Placement [#placement]

Pass `placement` to `ToastRegion` to choose the viewport corner or center edge.

<Preview>
  <PlacementToastExample />

  <Preview.Code>
    {`
          import {
            ToastPlacement,
            ToastProvider,
            ToastRegion,
            useToastManager,
            Button,
          } from "moduix";
          import { useState } from "react";

          export function App() {
            const [placement, setPlacement] = useState("bottom-right" as ToastPlacement);

            return (
              <ToastProvider>
                <AppShell placement={placement} onPlacementChange={setPlacement} />
                <ToastRegion placement={placement} />
              </ToastProvider>
            );
          }

          function AppShell({
            placement,
            onPlacementChange,
          }: {
            placement: ToastPlacement;
            onPlacementChange: (placement: ToastPlacement) => void;
          }) {
            const toastManager = useToastManager();
            return (
              <div>
                {placements.map((item) => (
                  <button
                    key={item}
                    type="button"
                    aria-pressed={item === placement}
                    onClick={() => onPlacementChange(item)}
                  >
                    {item}
                  </button>
                ))}
                <Button
                  onClick={() =>
                    toastManager.add({
                      title: "Placement",
                      description: \`Current placement: \${placement}\`,
                    })
                  }
                >
                  Show toast
                </Button>
              </div>
            );
          }
        `}
  </Preview.Code>

  <Preview.Data>
    {`
          const placements: ToastPlacement[] = [
            "top-left",
            "top-center",
            "top-right",
            "bottom-left",
            "bottom-center",
            "bottom-right",
          ];
        `}
  </Preview.Data>
</Preview>

### Always Expanded [#always-expanded]

Set `stackBehavior="expanded"` when the stack should stay readable without requiring hover or focus.

<Preview>
  <ExpandedToastExample />

  <Preview.Code>
    {`
          import { ToastProvider, ToastRegion, useToastManager, Button } from "moduix";

          export function App() {
            return (
              <ToastProvider>
                <AppShell />
                <ToastRegion placement="bottom-right" stackBehavior="expanded" />
              </ToastProvider>
            );
          }

          function AppShell() {
            const toastManager = useToastManager();

            return (
              <Button
                onClick={() =>
                  toastManager.add({
                    title: "Background task",
                    description: "Create several notifications to compare the expanded stack.",
                  })
                }
              >
                Create toast
              </Button>
            );
          }
        `}
  </Preview.Code>
</Preview>

### Global Manager [#global-manager]

Create a manager outside React when app services need to enqueue notifications through the same renderer.

<Preview>
  <GlobalManagerToastExample />

  <Preview.Code>
    {`
          import { createToastManager, ToastProvider, ToastRegion, Button } from "moduix";

          const toastManager = createToastManager();

          export function App() {
            return (
              <ToastProvider toastManager={toastManager}>
                <AppShell />
                <ToastRegion />
              </ToastProvider>
            );
          }

          function notifyFromService() {
            toastManager.add({
              title: "Global toast",
              description: "Created with createToastManager().",
            });
          }

          function AppShell() {
            return <Button onClick={notifyFromService}>Create global toast</Button>;
          }
        `}
  </Preview.Code>
</Preview>

### Custom Styles [#custom-styles]

Use `renderToast` when the application keeps the shared provider and region pattern but needs custom
layout, custom icons, or slot-level `className` styling for each toast.

<Preview>
  <CustomToastExample />

  <Preview.Code>
    {`
          import {
            Button,
            CloseLineIcon,
            InfoIcon,
            ToastProvider,
            ToastRegion,
            ToastRoot,
            ToastContent,
            ToastTitle,
            ToastDescription,
            ToastClose,
            useToastManager,
          } from "moduix";
          import styles from "./custom-toast.module.css";

          export function App() {
            return (
              <ToastProvider>
                <CreateToastButton />
                <ToastRegion
                  renderToast={(toast) => (
                    <ToastRoot toast={toast} className={styles.toast}>
                      <ToastContent className={styles.content}>
                        <InfoIcon className={styles.icon} />
                        <ToastTitle />
                        <ToastDescription />
                        <ToastClose aria-label="Close toast">
                          <CloseLineIcon className={styles.closeIcon} />
                        </ToastClose>
                      </ToastContent>
                    </ToastRoot>
                  )}
                />
              </ToastProvider>
            );
          }

          function CreateToastButton() {
            const toastManager = useToastManager();

            return (
              <Button
                onClick={() =>
                  toastManager.add({
                    title: "Custom composition",
                    description: "Every important part accepts className and custom children.",
                  })
                }
              >
                Create custom toast
              </Button>
            );
          }
        `}
  </Preview.Code>

  <Preview.CSS>
    {`
          .toast {
            --toast-bg: var(--color-primary);
            --toast-color: var(--color-primary-foreground);
            --toast-border-color: var(--color-primary);
            --toast-description-color: color-mix(
              in srgb,
              var(--color-primary-foreground) 72%,
              transparent
            );
            --toast-close-color: var(--color-primary-foreground);
            --toast-close-color-hover: var(--color-primary-foreground);
            --toast-close-bg-hover: color-mix(
              in srgb,
              var(--color-primary-foreground) 14%,
              transparent
            );
          }

          .content {
            grid-template-columns: auto minmax(0, 1fr);
            column-gap: var(--spacing-3);
            padding-right: 1.75rem;
          }

          .icon {
            grid-row: span 2;
            inline-size: 1.125rem;
            block-size: 1.125rem;
            color: currentColor;
          }

          .closeIcon {
            inline-size: var(--toast-close-icon-size, 1rem);
            block-size: var(--toast-close-icon-size, 1rem);
            flex: none;
          }
        `}
  </Preview.CSS>
</Preview>

### Anchored Toast [#anchored-toast]

Use `useAnchoredToastManager()` and `ToastAnchoredRegion` for transient feedback tied to a specific
button or control. Anchored and stacked toasts can share the same `ToastProvider`; each region
renders only the toast type it owns.

<Preview>
  <AnchoredToastExample />

  <Preview.Code>
    {`
          import {
            Button,
            ToastAnchoredRegion,
            ToastProvider,
            useAnchoredToastManager,
          } from "moduix";
          import { useRef } from "react";

          export function App() {
            return (
              <ToastProvider>
                <CopyButton />
                <ToastAnchoredRegion />
              </ToastProvider>
            );
          }

          function CopyButton() {
            const buttonRef = useRef(null as HTMLButtonElement | null);
            const anchoredToast = useAnchoredToastManager();

            function showCopiedToast() {
              if (!buttonRef.current) {
                return;
              }

              anchoredToast.show({
                anchor: buttonRef.current,
                description: "Copied",
                timeout: 1800,
              });
            }

            return (
              <Button ref={buttonRef} onClick={showCopiedToast}>
                Copy
              </Button>
            );
          }
        `}
  </Preview.Code>
</Preview>

### Stacked and Anchored Toasts [#stacked-and-anchored-toasts]

Render both regions under one provider when an app needs page-level notifications and contextual
feedback at the same time.

<Preview>
  <ToastAndAnchoredToastExample />

  <Preview.Code>
    {`
          import {
            Button,
            ToastAnchoredRegion,
            ToastProvider,
            ToastRegion,
            useAnchoredToastManager,
            useToastManager,
          } from "moduix";
          import { useRef } from "react";

          export function App() {
            return (
              <ToastProvider>
                <SaveButton />
                <CopyButton />
                <ToastRegion />
                <ToastAnchoredRegion />
              </ToastProvider>
            );
          }

          function SaveButton() {
            const toastManager = useToastManager();

            return (
              <Button
                onClick={() =>
                  toastManager.add({
                    title: "Saved",
                    description: "Changes were saved successfully.",
                  })
                }
              >
                Save changes
              </Button>
            );
          }

          function CopyButton() {
            const buttonRef = useRef(null as HTMLButtonElement | null);
            const anchoredToast = useAnchoredToastManager();

            function showCopiedToast() {
              if (!buttonRef.current) {
                return;
              }

              anchoredToast.show({
                anchor: buttonRef.current,
                description: "Copied",
                timeout: 1800,
              });
            }

            return (
              <Button ref={buttonRef} variant="outline" onClick={showCopiedToast}>
                Copy
              </Button>
            );
          }
        `}
  </Preview.Code>
</Preview>
