Nasaq

Toaster

Transient notifications. A themed, RTL-aware Sonner Toaster plus the re-exported toast() function.

PreviewOpen ↗

Code

import { Button, Toaster, toast } from "@fadymondy/nasaq/web";export function App() {  return (    <>      <Button onClick={() => toast.success("Invoice sent")}>Send invoice</Button>      <Toaster />    </>  );}

Alerts & Notifications · stable

Live examples and controls: Toaster in the lab.

Install

npx shadcn@latest add https://docs.nasaqui.com/r/toast.json

Short-lived feedback after an action ("Project renamed", "Could not reach the server"). It wraps Sonner: Toaster mounts the stack, themed from Nasaq tokens, and toast is Sonner's function, re-exported. You must mount <Toaster /> yourself, once, near the app root: without it toast() shows nothing.

When to use

  • Confirming a completed action, or reporting a background failure.
  • A reversible action with an "Undo" button.

When not to use

  • Errors the user must fix in a form: show them on the field.
  • Anything the user must decide on: use Dialog.
  • Persistent notifications: use NotificationItem in a Sheet.

Import

import { Toaster, toast } from "@fadymondy/nasaq/web";
// inside this monorepo: "@nasaq/web"

Quick start

import { Button, Toaster, toast } from "@fadymondy/nasaq/web";

export function App() {
  return (
    <>
      <Button onClick={() => toast.success("Invoice sent")}>Send invoice</Button>
      <Toaster />
    </>
  );
}

Toaster is not mounted for you by NasaqProvider or AppShell; render it yourself, exactly once (two mounted Toasters show every toast twice).

Apps that already use Sonner

Nasaq depends on sonner (exact version 2.0.8); it is not a peer dependency, so that the toast works with no setup. A <Toaster> only shows toasts from the same copy of Sonner, so an app that also imports sonner itself can end up with two stores and need two Toasters. Pick one:

  • Use Nasaq's toast everywhere. Import toast from @fadymondy/nasaq/web instead of sonner, and mount only Nasaq's Toaster. This always works.
  • Share one copy. Pin your own sonner dependency to the same version (2.0.8) so the package manager installs one copy; then toast from either import reaches either Toaster. Check with npm ls sonner or pnpm why sonner.

Anatomy

Toaster                     Sonner Toaster (fixed stack, bottom inline-end)
└─ toast                    Sonner toast, styled via toastOptions.classNames
   ├─ icon                  [data-icon], coloured for success / error / warning
   ├─ title
   ├─ description
   └─ action / cancel       buttons

There is no Nasaq data-slot; Sonner's own attributes (data-sonner-toast, data-type) apply.

API

Toaster

ComponentProps<typeof Sonner>: all Sonner Toaster props pass through (duration, visibleToasts, closeButton, expand, richColors, offset, toastOptions, ...). Set from Nasaq context (when a NasaqProvider is present):

PropValueDescription
themeresolvedTheme or "system"Follows the Nasaq light/dark theme.
dir"rtl" or "ltr"Follows isRtl.
position"bottom-left" in RTL, else "bottom-right"Inline-end corner.
containerAriaLabel"Notifications" or "الإشعارات"Accessible name of the toast region; Arabic when the Nasaq locale starts with ar.
toastOptionsNasaq classNames, merged with yoursThemed surface, description, action, cancel and status icon colours.

Props you pass are spread after these defaults and override them. toastOptions is the exception: your other options (duration, style, ...) pass through, and each of your toastOptions.classNames entries is merged (cn) after the Nasaq class for the same slot, so you extend the theme instead of wiping it.

toast

Sonner's function, unchanged.

CallUse
toast(message, options?)Neutral.
toast.success(message)Success (icon uses nq-success-text).
toast.error(message)Error (icon uses nq-danger-text).
toast.warning(message)Warning (icon uses nq-warning-text).
toast.info(message)Info.
toast.loading(message)Pending state.
toast.promise(promise, { loading, success, error })Follows a promise.
toast.dismiss(id?)Dismisses one or all.

Common options: description, duration, id, action: { label, onClick }, cancel: { label, onClick }.

Examples

Undo action

import { Button, Toaster, toast } from "@fadymondy/nasaq/web";

export function DeleteWithUndo() {
  return (
    <>
      <Button
        onClick={() =>
          toast("Issue deleted", { action: { label: "Undo", onClick: () => toast("Restored") } })
        }
      >
        Delete issue
      </Button>
      <Toaster />
    </>
  );
}

Promise, Arabic copy

import { Button, Toaster, toast } from "@fadymondy/nasaq/web";

export function SendAr() {
  return (
    <>
      <Button
        variant="primary"
        onClick={() =>
          toast.promise(new Promise((r) => setTimeout(r, 1200)), {
            loading: "جارٍ الإرسال…",
            success: "تم إرسال الفاتورة",
            error: "تعذّر الاتصال بالخادم",
          })
        }
      >
        إرسال الفاتورة
      </Button>
      <Toaster />
    </>
  );
}

Accessibility

Sonner renders a labelled <section aria-live="polite"> region; each toast is announced by screen readers.

KeyAction
Alt+TFocuses the toast region (Sonner default hotkey).
TabMoves to the action / cancel / close buttons of a toast.
  • Toasts auto-dismiss; do not rely on them for anything the user must read. Persist important results elsewhere.
  • Every status toast should carry text, not only an icon or colour.
  • The region label is localised through containerAriaLabel ("Notifications" / "الإشعارات"); pass your own to override.
  • Localise the message, action and cancel labels.

RTL & i18n

  • With NasaqProvider, the stack moves to the bottom-left in RTL and toast content flows right to left.
  • Without a provider it defaults to LTR, bottom-right.
  • The only built-in string is the region label (containerAriaLabel), English or Arabic by Nasaq locale.

Styling & tokens

  • Surface: bg-popover, text-popover-foreground, border-border, rounded-floating, text-body-sm. Shadow: shadow-floating, as other overlays.
  • Action button: bg-primary; cancel: bg-secondary. Icon colours: nq-success-text, nq-danger-text, nq-warning-text.
  • Sonner classes are overridden with ! important modifiers. Extend through toastOptions.classNames (merged with ours) or className.

Do / Don't

  • Do keep messages short and specific ("Invoice sent").
  • Do offer Undo instead of a confirm dialog for reversible actions.
  • Don't use toasts for errors that need action; keep them inline.
  • Don't fire several toasts for one action.
  • Don't mount more than one <Toaster />.

Lab

https://docs.nasaqui.com/?path=/docs/components-alerts-notifications-toast--docs

On this page