Sonner (Toast)
Transient, stacking notifications fired imperatively with toast().
@garn/ui/sonnerOn this page
Default
A button that fires a toast (with the Toaster mounted).
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.
npx garn-ui add sonner- 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).
toastThe 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
- 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 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
- 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).