Skip to content
garn

Sonner (Toast)

Transient, stacking notifications fired imperatively with toast().

Stablev0.4.2added in v0.1.0@garn/ui/sonner
On this page

Installation

garn is copy-in — the garn CLI writes this component's source into your project, so you own and can edit it. It resolves any base files and installs the npm dependencies below for you.

terminal
npx garn-ui add sonner
First time? Set up garn in your project
Registry
sonner
Deps
sonner
Registry deps
None — standalone

Import

import { Toaster, toast } from "@garn/ui/sonner";

Anatomy

The parts this component is built from — compose them to assemble it.

ToasterRequired[data-slot="toaster"]

The provider/host — mount exactly one near the app root (themed via toastOptions classNames).

toast

The imperative API: toast(message, opts) plus toast.success / .error / .promise / .dismiss. Not a component.

Props

The component's public props and their types.

No component-specific props — this is a thin wrapper over its native element.

Styling

Target these data-slots and states, and remap these tokens, to restyle without forking the component.

[data-slot="toaster"]

When to use

Confirm an action or surface a transient, non-blocking message that auto-dismisses — 'Saved', 'Copied', 'Undo'.

Reach for something else when

  • A persistent inline status (use alert)
  • a decision the user must make (use alert-dialog)
  • a critical error that must not be missed (don't rely on an auto-dismissing toast).

Overview

Sonner confirms an action or surfaces a transient, non-blocking message that auto-dismisses — "Saved", "Copied", "Undo". Mount exactly one Toaster near the app root, then fire toasts imperatively with toast(message, opts) and its .success / .error / .promise helpers. It's for moments that don't need a response; for a persistent message that stays on the page use Alert, and for a decision the user must make use a Dialog.

Guidelines

Use toasts for confirmation, not for anything required. A toast disappears — never put an error a user must act on, or the only copy of important information, in one. toast.promise is ideal for tying a toast to an async action's pending/success/error states.

Keep them short and offer Undo over confirm-first. One line is plenty; where an action is reversible, ship it optimistically with an Undo toast instead of interrupting with a dialog. Don't stack many toasts at once — collapse or queue them.

Mount one Toaster and respect timing. A single host keeps positioning and theming consistent; let messages auto-dismiss but give error toasts a longer dwell (or an explicit close) so they're readable. They're announced politely — don't rely on them as the sole signal for critical state.

Best practices

Do
  • Render exactly one <Toaster /> near the app root; call toast() from anywhere.
  • Keep messages short; attach an action (e.g. Undo) when useful.
  • Use toast.success / toast.error / toast.promise to match intent.
Don't
  • Don't mount multiple Toasters.
  • Don't put essential, time-limited actions only in a toast.
  • Don't use a toast where a persistent banner (alert) belongs.

Content guidelines

  • Keep a toast to a short confirmation (“Changes saved”) — don't pack detail into it.
  • Label any action (“Undo”) by outcome, and never put a critical-only action in a toast.

Troubleshooting

toast() does nothing / no toast appears.

Cause. No <Toaster /> is mounted in the tree.

Fix. Render a single <Toaster /> once at the app root; then toast() works from anywhere.

Duplicate or misplaced toasts.

Cause. More than one Toaster is mounted.

Fix. Mount exactly one Toaster for the whole app.

Accessibility

Role
status
AA4.1.3Status MessagesA2.2.1Timing Adjustable
  • Sonner renders toasts in an aria-live region so they're announced without stealing focus.
  • Keep toast text self-contained; if an action is essential, don't make a brief auto-dismissing toast the only way to reach it.
  • Toasts are reachable/dismissable via the keyboard (focus the region with the hotkey, default Alt/⌥ + T).