nalarx-ui
Components

Toast

A short notification card in one shared bottom-right column. Tone rides on the border and text colour.

bunx shadcn@latest add @nalarx/toast

Usage

For one message held in parent state, Toast is enough. It dismisses itself after 2.4s, or 3.6s for kind: "err".

import { Toast, type ToastMessage } from "@/components/ui/nx/Toast";

const [toast, setToast] = useState<ToastMessage | null>(null);
setToast({ msg: t("members.invited") });

<Toast toast={toast} onDismiss={() => setToast(null)} />

For several cards, a warning, or a card that opens something, compose ToastRegion and ToastCard:

<ToastRegion>
  {builds.map((build) => (
    <ToastCard
      key={build.id}
      tone={build.failed ? "warn" : "ok"}
      onActivate={() => open(build.id)}
      activateLabel={t("dashboards.open", { name: build.name })}
      onDismiss={() => dismiss(build.id)}
      autoDismissMs={6000}
    >
      {build.message}
    </ToastCard>
  ))}
</ToastRegion>

Every region joins one fixed column on document.body, so toasts from different screens stack instead of covering each other, and a transformed ancestor cannot pull them off screen. The column sits 24px from the bottom-right corner; on phones (under 768px) it moves to the top right, below a 52px app bar, so it does not cover a chat composer.

Tones (ok, err, warn), a card whose body is a button, and one without a dismiss button:

Invitation sent
Could not revoke the share link
The dashboard build stopped. Try again.
Saved
Invitation sent
Could not revoke the share link
The dashboard build stopped. Try again.
Saved

Real toasts in the region; hover one to hold it:

Keyboard

Toasts do not take focus when they appear, and there is no Escape shortcut. The region sits at the end of document.body, so Tab reaches it after the rest of the page: first the card body when it is a button (onActivate), then its Dismiss button. Hover or focus anywhere inside a card holds its auto-dismiss countdown.

A card without onActivate is an <output>, so screen readers announce its text politely.

Props

ToastCard:

PropTypeDefault
tone"ok" | "err" | "warn""ok"warn: not finished, but the reader can still act on it.
childrenReactNodeThe message line.
onActivate() => voidMakes the whole body a button.
activateLabelstringAccessible name of that button.
onDismiss() => voidShows the Dismiss button.
autoDismissMsnumberCalls onDismiss after this long; hover and focus hold it.
dismissLabelstringdismiss stringVisible text of the button.
dismissAriaLabelstringdismissNotification stringIts accessible name.

ToastRegion takes ariaLabel (default: the toastRegion string) and children. Toast takes toast: { msg, kind?: "ok" \| "err" } \| null and onDismiss.

Replaces

Web NxToast.tsx (NxToastRegion, NxToastCard, NxToastTone) and Toast.tsx, and the Platform's own Toast.tsx (top-right, status dot, no dismiss button). The facades keep NxToastRegion, NxToastCard and Toast. Web's unused base/Toast.tsx (Base UI toast manager) is not part of this item.

On this page