Toast
A brief notification that appears in the corner and dismisses itself.
const toast = useAppToast()toast.add({ title: 'Your changes have been saved',})Props
| Name | Type | Default |
|---|---|---|
| title | string | - |
| description | string | - |
| variant | 'success' | 'warning' | 'error' | 'default' | 'default' |
| icon | string | - (no icon shown) |
| actions | { label, variant?: ButtonVariant, onClick, ... }[] | - |
| close | boolean | object | false |
Guidelines
Do
- Call
useAppToast().add({ title, variant })for feedback about something the user just did (saved, signed in, sent a code) - every real usage inapps/frontend's auth flows follows this shape. - Leave
iconunset for the common case - most toasts in the app are justtitle(+ optionaldescription), no icon at all. - For a toast that needs
duration: 0or a stableid- a persistent toast with required actions, or one tied to a specific one-off event so a duplicate trigger updates it instead of stacking a second one - use Nuxt UI's rawuseToast()directly, sinceuseAppToast()doesn't expose either option. Seeapp.vue's cookie-consent toast andaccount.vue's connected-account toasts.
- Expect
success/warning/error/defaultto render on the design system's ownsurface-semantic-*/surface-popoverbackground with a matchingstroke-semantic-*/stroke-strongring (light pastel + light stroke in light mode, near-black + darker stroke in dark mode for the semantic ones) rather than Nuxt UI's vibrantbg-{color}/ring-{color}- full opacity, not a translucent tint, so it reads clearly regardless of what's behind the toast. - Expect at most 3 toasts visible at once, collapsed behind the front one (only expanding on hover) - matching shadcn's own Sonner stacking. A 4th toast fades the oldest out through the normal dismiss animation rather than cutting it off instantly.
Don't
- Don't call Nuxt UI's raw
useToast()directly unless you specifically needdurationorid, whichuseAppToast()doesn't expose - otherwise useuseAppToast()(packages/foundation/app/composables/useAppToast.ts) instead, the same way you'd reach forAlert/Buttonrather thanUAlert/UButtondirectly. - Don't use a toast for something the user needs to act on before continuing (an unsaved-changes warning, a limit reached) - use
Alertinstead; a toast can be missed or auto-dismiss before it's read. - Don't restyle a toast per call site (
:uioverrides, custom classes) - the shared look (rounded corners, shadow, background per state) is set once, globally, inapp.config.ts'stoast/toasterkeys, since there's no per-instance component to own it locally.
- Don't fire more than one toast for the same action - if a mutation can both succeed and fail, that's one toast with the outcome-appropriate
variant, not two. - Don't rely on the toast's countdown being visible to the user - the progress bar is turned off globally (
toaster.defaultVariants.progress: false), sodurationstill controls when it auto-dismisses, just without a visual cue. - Don't add a close button expecting it by default - Nuxt UI's own default shows one on every toast; this design system defaults
closetofalseglobally, so set it explicitly when a toast genuinely needs manual dismissal.
Examples
Warning
A risky-but-not-blocking outcome, like needing a second factor.
toast.add({ title: 'Second factor required', variant: 'warning',})Error
Feedback that an action failed.
toast.add({ title: 'Something went wrong', variant: 'error',})With icon
A deliberate glyph for a specific, recognizable event.
toast.add({ title: 'Password updated', variant: 'success', icon: 'i-lucide-lock',})With actions
Auto-dismissing, but with a quick response action - variant here is this design system's own Button vocabulary, not Nuxt UI's raw color/variant.
toast.add({ title: 'Finding marked as resolved', actions: [ { label: 'Undo', variant: 'Secondary', onClick: () => { /* ... */ } }, { label: 'Dismiss', variant: 'Ghost', onClick: () => { /* ... */ } }, ],})Persistent with actions
A toast that stays until the user responds, for actions it can't auto-dismiss past.
const toast = useToast() // duration/id aren't available on useAppToast() - see its own filetoast.add({ title: 'We use cookies to improve your experience', duration: 0, close: true, actions: [ { label: 'Accept', color: 'secondary', variant: 'solid', onClick: () => { /* ... */ } }, { label: 'Opt out', color: 'neutral', variant: 'ghost', onClick: () => { /* ... */ } }, ],})