Skip to content

Actions

Toast

A short status message that appears, announces itself, and leaves on its own.

When to use it: Use it to confirm background results such as saves; keep anything needing a decision in a dialog.

On this page

Example

Toast.tsxtsx
import { Button } from "@comp0/react";
import { Toast, ToastDismiss, ToastProvider, ToastRegion, useToast } from "@comp0/react";
import { XMarkIcon } from "@heroicons/react/16/solid";

function Triggers() {
  const { notify } = useToast();
  return (
    <div className="flex flex-wrap gap-2">
      <Button
        className="rounded bg-teal-600 px-3 py-2.5 text-base text-white sm:py-2 sm:text-sm"
        onClick={() => notify("Saved")}
      >
        Save
      </Button>
      <Button
        className="rounded border border-red-950/10 px-3 py-2.5 text-base text-red-700 sm:py-2 sm:text-sm dark:border-red-200/10 dark:text-red-300"
        onClick={() =>
          notify("Connection lost. Changes stopped syncing.", { kind: "alert", timeout: null })
        }
      >
        Go offline
      </Button>
    </div>
  );
}

export function Example() {
  return (
    <ToastProvider>
      <Triggers />
      <ToastRegion className="inset-auto right-4 bottom-4 m-0 flex w-72 flex-col gap-2 border-0 bg-transparent p-0">
        {(toast) => (
          <Toast
            toast={toast}
            className="flex items-start justify-between gap-3 rounded border border-zinc-950/10 bg-white p-3 text-base text-zinc-900 shadow-lg sm:text-sm data-[kind=alert]:border-red-600/30 data-[kind=alert]:text-red-700 dark:border-white/10 dark:bg-zinc-900 dark:text-zinc-50 dark:data-[kind=alert]:border-red-400/30 dark:data-[kind=alert]:text-red-300"
          >
            <span>{toast.content}</span>
            <ToastDismiss className="rounded p-0.5 text-zinc-500 hover:bg-zinc-950/10 hover:text-zinc-800 dark:text-zinc-400 dark:hover:bg-white/10 dark:hover:text-zinc-100">
              <XMarkIcon className="size-4" aria-hidden="true" />
            </ToastDismiss>
          </Toast>
        )}
      </ToastRegion>
    </ToastProvider>
  );
}

Anatomy

Dashed frames are invisible state providers; shaded shapes own real DOM. Numbered pins match the list below.

A wireframe sketch of the assembled component. Each numbered marker matches a part in the list that follows.

  1. ToastProvider

    Owns the notification queue; it owns no DOM. Does not add a DOM element.

  2. useToast

    Hook returning notify and dismiss; throws outside ToastProvider. Does not add a DOM element.

  3. ToastRegion

    Labelled live region shown in the top layer only while toasts exist; hover or focus pauses auto-dismiss timers. Owns a DOM element.

  4. Toast

    One notification; role=status for polite kinds and role=alert for urgent ones. Owns a DOM element.

  5. ToastDismissOptional

    Native button pre-wired to dismiss its surrounding toast. Owns a DOM element.

Step by step

  1. 1

    Add the main part

    Wrap the app in ToastProvider and call notify from useToast where results happen.

  2. 2

    Add the supporting parts

    Add one ToastRegion whose render prop returns a Toast with a ToastDismiss inside.

  3. 3

    Make the behavior clear

    Use kind "alert" plus timeout null for urgent messages people must not miss.

    Exampletsx
    <ToastRegion>{(toast) => <Toast toast={toast}>{toast.content}<ToastDismiss /></Toast>}</ToastRegion>

Keyboard

Reaches the dismiss button and other controls inside each toast.
Esc
Intentionally not a global shortcut; dismissal stays on the buttons inside the region.

Forms and accessibility

Toasts do not create native form values.

Accessibility checklist

  • Keep messages short and self-contained; role=status announces politely and role=alert interrupts, so reserve alert for urgent problems.
  • Auto-dismiss timers pause while the region is hovered or contains focus, and sticky toasts (timeout null) stay for anything people must act on.
  • The toast renders its live-region role and content in the same commit, which browsers announce for items appended one at a time; keep updates as new toasts instead of mutating an existing one.

API reference

Importtsx
import { Button, Toast, ToastDismiss, ToastProvider, ToastRegion, useToast } from "@comp0/react";

ToastProvider

Context only

Owns the notification queue; it owns no DOM.

PropTypeDescription
childrenReactNodeApp content plus one ToastRegion; call useToast anywhere inside.

useToast

Context only

Hook returning notify and dismiss; throws outside ToastProvider.

PropTypeDescription
notify(content, options?)(content: ReactNode, options?: { kind?: "status" | "alert"; timeout?: number | null }) => stringQueues a toast and returns its id; kind defaults to status, timeout to 6000 ms, and null keeps it until dismissed.
dismiss(id)(id: string) => voidRemoves a queued toast by id.

ToastRegion

DOM element

Labelled live region shown in the top layer only while toasts exist; hover or focus pauses auto-dismiss timers.

PropTypeDescription
children(toast: ToastRecord) => ReactNodeRender prop that returns one Toast per queued record.
aria-labelstringRegion name for assistive technology; defaults to "Notifications".
forceMountbooleanKeep the region rendered while the queue is empty.

Toast

DOM element

One notification; role=status for polite kinds and role=alert for urgent ones.

PropTypeDescription
toastToastRecordThe queued record this item renders.
childrenReactNodeCustom layout; defaults to the record's content.

ToastDismiss

OptionalDOM element

Native button pre-wired to dismiss its surrounding toast.

PropTypeDescription
aria-labelstringAccessible name; defaults to "Dismiss notification".

Style hooks

Attributes that appear while a state is true. Target them with Tailwind data variants such as data-open:bg-zinc-100, or with any CSS selector.

[data-kind=alert]

on Toast

The toast is urgent.
[data-kind=status]

on Toast

The toast is polite.
:popover-open

on ToastRegion

The region is shown in the top layer.

Keep exploring