Components

Toast (Sonner)

Transient, non-blocking feedback after an action. Built on Sonner (shadcn's official toast library since 2024, replacing the deprecated Radix Toast). Chrome per Figma spec: bg-popover rounded-md border shadow-md p-4 gap-2, title font-medium 14, description muted 14, optional Phosphor icon size-5, optional primary/secondary action button. Yuno convention: success messages include 'successfully' + period.

Updated Jul 30, 2026 by Leonardo Posada

Anatomy

Two shapes share the same chrome. The default Sonner is a single-row toast (icon + text stack + optional action). Sonner / Notification is a richer variant that top-aligns, stacks a Progress bar between text and action, and adds an explicit close X — reserved for long-running or dismissible operations.

Exporting - Payments.csv

Loading...

Cancel
  1. 1
    Toaster (Root)

    The <Toaster /> mounted once at the app root. Owns position, theme, icons, and the classNames overrides that apply to every toast. Yuno rule for positioning: default toasts render bottom-center of the viewport (48px from bottom); Sonner / Notifications override to top-right — 88px from top (64px topbar + 24px gap) and 24px from the right edge — via toast(..., { position: 'top-right' }).

  2. 2
    Icon slot

    Optional Phosphor size-5 icon at the left. Yuno wires five weights=light: CheckCircle (success) · Info (info) · Warning (warning) · WarningCircle (error) · CircleNotch (loading, animated with animate-spin).

  3. 3
    Title

    font-medium text-sm text-popover-foreground. First line of the toast. Keep it short — one clear statement of what happened.

  4. 4
    Description

    Optional. font-normal text-sm text-muted-foreground. Sits below the title with gap-[2px]. Use when the title alone doesn't carry enough context (a file name, a next-step hint).

  5. 5
    Action button

    Optional primary button on the right (h-6 px-2 rounded-sm text-xs font-medium bg-primary). Canonical labels: 'Undo' (reversible mutation), 'Retry' / 'Try again' (recover from an error), 'Download again' (re-run an idempotent op).

  6. 6
    Cancel button

    Optional secondary button (bg-secondary text-secondary-foreground). Canonical label: 'Cancel'. Used alone or as a companion to the action.

  7. 7
    Progress bar (Notification only)

    h-2 rounded-full track with a primary-tinted fill. Sits between the text stack and the action row in a Sonner / Notification. Wire it to the actual operation progress — never fake it.

  8. 8
    Close X (Notification only)

    Explicit dismiss control (16px X icon) top-right of a Sonner / Notification. Enabled globally via <Toaster closeButton /> or per-toast via the close button visibility.

States

Default toasts animate in from the bottom-center (slide up + fade + scale). Notifications animate in from the top-right corner. Idle: bg-popover with shadow-md drop-shadow. Focus (keyboard swipe target): outer ring-2 ring-black/20 + shadow-md — Sonner handles this on its own; do not override. Loading: the icon rotates via animate-spin. Hover/near a toast: Sonner expands the stack if `expand` is enabled — the kit leaves it collapsed so the surface stays quiet.

Toast is transient — don't put anything critical inside
Toasts auto-dismiss (5s default) and disappear on scroll. They're for confirming an action already committed or surfacing a recoverable error — never for content the user must acknowledge or a confirmation the app depends on. Blocking decisions belong in Alert Dialog; permanent status belongs in Alert or Badge; long-running progress belongs in Sonner / Notification (which duration:Infinity turns into a persistent toast).

Recipes

Ready-to-copy compositions covering the most common Yuno usages of this atom.

Success — Yuno canonical ('successfully.' period)

Every success message follows the Yuno copy convention: verb + noun + 'successfully' + period. Uses CheckCircle (light) in text-success as the icon. Keep the message under 60 characters so it never wraps.

toast.success("Rule created successfully.");
Success with Undo

For reversible mutations (delete a rule, remove a member, unarchive an item), pair the success message with an Undo action that reverts the change. Sonner's action prop takes { label, onClick } and renders the primary h-6 button. Undo timers should mirror the toast duration.

toast.success("Rule deleted successfully.", {
  action: { label: "Undo", onClick: () => restoreRule() },
});
Error — Try again

For recoverable failures (a network hiccup, a 500 the user can retry). Uses WarningCircle (light) in text-destructive. Copy: 'Something went wrong. Try again.' + action { label: 'Try again', onClick: retry }.

toast.error("Something went wrong. Try again.", {
  action: { label: "Try again", onClick: () => retry() },
});
Warning — Blocked action

For blocked-but-non-critical actions (out-of-range dates, unsaved changes). Uses Warning (light) in text-amber-500. Keep it stateless — describe why the action didn't complete, don't ask a question.

toast.warning("Event start time cannot be earlier than 8am.");
Info — Contextual tip

For contextual FYIs (a config just changed, a new report is ready). Uses Info (light) in text-primary. Use sparingly — inline hints usually beat a toast for FYIs.

toast.info("Be at the area 10 minutes before the event time.");
Loading → Success (promise)

For operations you already have a Promise for (async save, remote export). toast.promise(fn, { loading, success, error }) fires the loading toast immediately, then swaps to success or error when the promise resolves. Uses CircleNotch (light) with animate-spin as the loading icon.

toast.promise(saveRule(), {
  loading: "Saving rule…",
  success: "Rule saved successfully.",
  error: "Could not save the rule. Try again.",
});
Notification — long-running export (progress + Cancel)

Uses the Sonner / Notification variant for operations the user watches finish. Fire it with position:'top-right' so it renders 88px from the top (below the topbar) and 24px from the right edge — the Yuno canon for notifications. duration:Infinity + a Progress bar rendered inside description + Cancel action + close X. Canonical Yuno case: 'Exporting - File title.csv' with a live progress track. Never fake the progress — wire it to the real percentage.

toast("Exporting - File title.csv", {
  description: (
    <div className="flex flex-col gap-2">
      <span>Loading…</span>
      <Progress value={progress} />
    </div>
  ),
  duration: Infinity,
  position: "top-right",
  closeButton: true,
  action: { label: "Cancel", onClick: () => cancelExport() },
});
Notification — success confirmation (Download again?)

Rich confirmation with CheckCircle (fill) in text-success. Same top-right positioning + duration:Infinity so the user decides. Canonical Yuno case: after a completed export, ask 'Download file again?' with a primary 'Download again' action.

toast.success("Download file again?", {
  description: "Do you want to download 'Pagos Argentina.csv' again?",
  duration: Infinity,
  position: "top-right",
  closeButton: true,
  action: { label: "Download again", onClick: () => downloadAgain() },
});
Notification — error confirmation (Try again)

Rich confirmation with WarningCircle (fill) in text-destructive. Canonical Yuno case: 'Failed export! - File title.csv' with a primary 'Try again' action. Description explains what went wrong; action offers the recovery step.

toast.error("Failed export! - File title.csv", {
  description: "We're sorry, something went wrong and we couldn't download your report.",
  duration: Infinity,
  position: "top-right",
  closeButton: true,
  action: { label: "Try again", onClick: () => retryExport() },
});
Notification — warning acknowledgement (Got it!)

Rich confirmation with Warning (fill) in text-amber-500 for non-critical warnings the user should acknowledge. Canonical Yuno case: 'Failed export! - File title.csv' explaining a slight delay, with a single 'Got it!' primary action to dismiss.

toast.warning("Failed export! - File title.csv", {
  description: "The report's larger size is causing a slight delay. We're processing the download and will notify you when it's done.",
  duration: Infinity,
  position: "top-right",
  closeButton: true,
  action: { label: "Got it!", onClick: (id) => toast.dismiss(id) },
});

Import

Copy the Toaster mount once in the app layout, then call toast() from anywhere. The Yuno wrapper re-exports the sonner toast() function so you can import both from the same path.

// app/layout.tsx — mount once
import { Toaster } from "@/components/ui/sonner";

export default function RootLayout({ children }) {
  return (
    <html>
      <body>
        {children}
        <Toaster />
      </body>
    </html>
  );
}

// anywhere — fire a toast
import { toast } from "sonner";

toast.success("Rule created successfully.");

Props

The Yuno wrapper opinionates position, icons, and classNames; you rarely need to pass anything to <Toaster />. The props you actually work with are the toast() function options — Sonner's public API for firing individual toasts.

PropTypeDefaultDescription
toast(message, options)(message: ReactNode, options?: ToastOptions) => idDefault toast. Renders the message as the title. Returns the toast id (use with toast.dismiss).
toast.success / .error / .warning / .info(message, options?)Tone-tinted toasts. Wire the Phosphor icon automatically via the Toaster icons prop.
toast.promise(fn, { loading, success, error })(promise, { loading, success, error })Fires the loading toast immediately, then swaps to success or error when the promise resolves. Handles the async lifecycle for you.
options.descriptionReactNodeSecond line under the title. Rendered muted-foreground; use for context (file name, next step).
options.action{ label: string; onClick: () => void }Primary action button (Undo / Retry / Download again). Auto-styled as bg-primary text-xs h-6.
options.cancel{ label: string; onClick?: () => void }Secondary Cancel button. Auto-styled as bg-secondary text-xs h-6.
options.durationnumber | Infinity5000Milliseconds before auto-dismiss. Pass Infinity for Sonner / Notification recipes the user must dismiss themselves.
options.position"bottom-center" | "top-right" | …"bottom-center"Overrides the default Toaster position for this toast. Use 'top-right' for the Sonner / Notification variant — Yuno canon.
options.closeButtonbooleanfalseRenders the top-right X. Yuno enables this on every Sonner / Notification recipe.
options.idstring | numberAssign a stable id to update or coalesce a toast (toast(msg, { id: 'export-123' }) fired twice replaces the first).
options.iconReactNodeOverride the default tone icon for this toast. Rarely needed — the Toaster icons prop already wires Phosphor.
toast.dismiss(id?)(id?: string | number) => voidDismiss a single toast by id, or dismiss all if no id is passed.

When to use

  • Confirm a successful action ('Rule created successfully.').
  • Show a non-blocking error the user can dismiss or retry.
  • Offer an Undo affordance for reversible mutations (delete, archive, remove).
  • Long-running background operations with progress (export, upload, sync) — use the Sonner / Notification variant.
  • Contextual FYIs the user doesn't need to acknowledge (a report is ready, a webhook fired).

When not to use

  • The user MUST acknowledge — use AlertDialog.
  • Persistent status the user needs to see later — use Alert (inline banner) or Badge.
  • Form-field errors — inline error text under the input, not a toast.
  • Feature onboarding / tutorials — use a Popover.
  • Notifications the user should be able to review later — use a notifications tray (Popover on the bell).

Usage

Do
  • Follow the Yuno copy convention: verb + noun + 'successfully' + period.
  • Keep the primary message under 60 characters so it never wraps.
  • Include an Undo action for every reversible mutation.
  • Use the Sonner / Notification variant (duration:Infinity + close X) for anything > 5s.
  • Wire the Progress bar to real progress — never fake it.
  • Use Phosphor weight=light — the kit's Toaster already sets this via icons prop.
Don't
  • Don't fire multiple toasts for the same event — coalesce them.
  • Don't put required actions inside a default toast — it auto-dismisses. Use Notification (duration:Infinity) for anything the user must decide.
  • Don't rely on toast for error states that block progress — those belong inline.
  • Don't stack colored borders / tinted backgrounds by tone — Yuno keeps the surface neutral, tone lives only in the icon color.
  • Don't change the default position of regular toasts — bottom-center is the Yuno canon. Notifications override to top-right per-toast via toast(..., { position: 'top-right' }); nothing else moves.
  • Don't mount more than one <Toaster /> — Sonner is a singleton.

Related

Cross-links to atoms and patterns you may reach for next.

  • AlertInline banner for persistent status. Toast is transient; Alert stays until dismissed or the state clears.
  • Alert dialogBlocking confirmation the user MUST acknowledge — use for irreversible or destructive decisions.
  • CalloutContextual FYI inside a page. Toast is transient; Callout stays with the surrounding content.
  • ButtonPowers the action + cancel buttons inside a toast (h-6 primary or secondary).
  • ProgressUsed inside the Sonner / Notification recipe for long-running operations.
  • IconographyPhosphor weight=light for CheckCircle / Info / Warning / WarningCircle / CircleNotch.