Components
Toaster
shadcn's Sonner with goo. Toasts drop in as blobs, merge when stacked, and drip away when they leave.
Customize
Installation
GoopToaster wraps vue-sonner, the same library behind shadcn-vue's Sonner. vue-sonner is a peer dependency, so install it yourself:
pnpm add vue-sonner
Nuxt
pnpm add @goopui/nuxt vue-sonner
export default defineNuxtConfig({
modules: ['@goopui/nuxt'],
css: ['vue-sonner/style.css'],
})
The module auto-imports GoopToaster, adds goop.css, and keeps a single copy of vue-sonner, so the toaster and your toast() calls share one queue.
Vue
pnpm add @goopui/vue vue-sonner
@import "tailwindcss";
@import "@goopui/vue/goop.css";
@import "vue-sonner/style.css";
Usage
Mount GoopToaster once, near the root of your app. Then call toast() from vue-sonner anywhere, the same as with shadcn-vue's Sonner:
<script setup lang="ts">
// Nuxt auto-imports GoopToaster. In plain Vue, import it:
import { GoopToaster } from '@goopui/vue'
</script>
<template>
<NuxtPage />
<GoopToaster />
</template>
<script setup lang="ts">
import { toast } from 'vue-sonner'
</script>
<template>
<GoopButton variant="outline" @click="toast('Event has been created')">
Show toast
</GoopButton>
</template>
GoopToaster takes every vue-sonner Toaster prop (position, expand, richColors, closeButton, duration, toastOptions, ...). Its defaults match shadcn's: the popover tokens for color, rounded-2xl toasts, and lucide icons.
Calling toast()
There is no goopUI toast. Use vue-sonner's, with all its options.
import { toast } from 'vue-sonner'
toast('Event has been created')
toast('Event has been created', { description: 'Sunday, December 03, 2023 at 9:00 AM' })
toast.success('Changes saved')
toast.error('Could not reach the server')
toast.info('A new version is available')
toast.warning('Your trial ends tomorrow')
toast('Message archived', {
action: { label: 'Undo', onClick: () => toast('Restored') },
})
toast.promise(save(), {
loading: 'Saving...',
success: (data) => `${data.name} has been added`,
error: 'Something went wrong',
})
The vue-sonner docs cover the rest: custom components, durations, dismissing, multiple toasters with toasterId.
Behavior
All the goo for a stack is drawn in one aria-hidden layer behind the toasts. The toasts stay real, unfiltered DOM, so text, buttons, and focus work as in Sonner. Each toast's own background, border, and shadow are handed to the goo layer.
- Drop in (
dropIn). A new toast arrives as a round blob at the toaster's edge and inflates into the toast. It overshoots, trails goo back toward the edge until the trail snaps, then the far side sloshes. - Merge (
merge). Stacked toasts are joined by fat goo necks where they touch. Hover the stack to expand it and the necks stretch, thin, and snap. Collapse it and they form again. - Drips (
drips). A toast that leaves sags and pinches while a few drops neck off its bottom edge and fall. Swipe one away and the drops fly the way you swiped. - Layout never changes. The goo layer is fixed behind the toaster, and the filter only covers the stack's bounding box.
Props
GoopToaster takes vue-sonner's Toaster props plus class, and adds the goo props.
| Prop | Type | Default | Notes |
|---|---|---|---|
goo | boolean | true | Master switch. false renders exactly shadcn's Sonner. |
dropIn | boolean | number | true | New toasts drop in as a blob, overshoot, and slosh. |
merge | boolean | number | true | Stacked toasts merge with goo necks that stretch and snap as the stack expands. |
drips | boolean | number | true | Leaving toasts drip off. Swipe-out flings the goo the swipe's way. |
speed | number | 1 | Animation speed multiplier. |
preset | 'subtle' | 'playful' | 'wild' | 'playful' | The feel. Falls back to the app config, then --goop-preset. |
position | 'top-left' | 'top-center' | 'top-right' | 'bottom-left' | 'bottom-center' | 'bottom-right' | 'bottom-right' | vue-sonner's Toaster prop: where the stack sits. |
Effect props take true, false, or a number from 0 to 2. Props win over the app-wide config (GoopPlugin or the module options), which wins over the preset.
<GoopToaster position="top-center" preset="wild" :drips="false" />
GoopToaster also exposes handle, the core ToasterHandle (null before mount or with goo off). handle.refresh() re-scans the toasts and redraws.
Colors
Toasts use shadcn's popover tokens, and the goo paints whatever background the toast has: --popover by default, the status colors with richColors, or a class you set through toastOptions. Change the tokens and the goo follows, in light and dark mode.
Accessibility
Sonner's live region and focus handling are untouched, because the toasts are the real elements. The goo layer is aria-hidden and ignores the pointer. Under reduced motion the toasts keep their goo bodies and the effects turn off: no drop in, no necks stretching, no drips. See Accessibility & reduced motion.