Convert Figma logo to code with AI

anl331 logogoey-toast

A gooey, morphing toast component built on Sonner with Framer Motion animations

1,167
52
1,167
1

Quick Overview

Error generating quick overview

Convert Figma logo designs to code with AI

Visual Copilot

Introducing Visual Copilot: A new AI model to turn Figma designs to high quality code using your components.

Try Visual Copilot

README

gooey-toast

gooey-toast

Live Demo & Docs

Features

  • Organic blob morph animation (pill → blob → pill)
  • Five toast types: default, success, error, warning, info
  • Promise toasts with loading → success/error transitions
  • Action buttons with optional success label morph-back
  • Description body supporting strings and React components
  • Configurable display duration and bounce intensity
  • Custom fill color, border color, and border width
  • CSS class overrides via classNames prop
  • 6 positions with automatic horizontal mirroring for right-side positions
  • Center positions with symmetric morph animation
  • Hover pause: hovering an expanded toast pauses the dismiss timer
  • Hover re-expand: hovering a collapsed pill re-expands the toast
  • Pre-dismiss collapse animation
  • In-place toast updates via gooeyToast.update()
  • Dismiss by type filter: gooeyToast.dismiss({ type: 'error' })
  • Dark mode and RTL layout support
  • Animation presets: smooth, bouncy, subtle, snappy
  • Timestamp display on expanded toasts with optional showTimestamp toggle
  • Close button with configurable position (top-left / top-right)
  • Countdown progress bar with hover-pause and re-expand
  • Keyboard dismiss (Escape) and swipe-to-dismiss on mobile
  • Toast queue with configurable overflow strategy
  • Dismiss callbacks: onDismiss and onAutoClose

Installation

npm install goey-toast

shadcn/ui

npx shadcn@latest add https://goey-toast.vercel.app/r/goey-toaster.json

This installs a thin wrapper component at components/ui/goey-toaster.tsx and auto-installs the goey-toast and framer-motion packages.

AI Agents (Skill)

goey-toast ships a bundled Agent Skill (SKILL.md) so coding agents (Claude Code, Cursor, etc.) know how to install and use it correctly — the required <GooeyToaster /> mount, the styles.css import, and the full API.

Install from the skills.sh registry:

npx skills add anl331/goey-toast

Or copy the skill into your project from the package itself:

npx goey-toast add-skill            # -> .claude/skills/goey-toast/SKILL.md
npx goey-toast add-skill --agents   # also append an AGENTS.md pointer
npx goey-toast add-skill --dir .cursor/skills/goey-toast

Peer Dependencies

goey-toast requires the following peer dependencies:

npm install react react-dom framer-motion
PackageVersion
react>= 18.0.0
react-dom>= 18.0.0
framer-motion>= 10.0.0

CSS Import (Required)

You must import the goey-toast stylesheet for the component to render correctly:

import 'goey-toast/styles.css'

Add this import once in your app's entry point (e.g., main.tsx or App.tsx). Without it, toasts will appear unstyled.

Quick Start

import { GooeyToaster, gooeyToast } from 'goey-toast'
import 'goey-toast/styles.css'

function App() {
  return (
    <>
      <GooeyToaster position="bottom-right" />
      <button onClick={() => gooeyToast.success('Saved!')}>
        Save
      </button>
    </>
  )
}

API Reference

gooeyToast Methods

gooeyToast(title, options?)              // default (neutral)
gooeyToast.success(title, options?)      // green
gooeyToast.error(title, options?)        // red
gooeyToast.warning(title, options?)      // yellow
gooeyToast.info(title, options?)         // blue
gooeyToast.promise(promise, data)        // loading -> success/error
gooeyToast.update(id, options)           // update an existing toast in-place
gooeyToast.dismiss(idOrFilter?)          // dismiss one, by type, or all toasts

gooeyToast.update(id, options)

Updates an existing toast in-place without removing and re-creating it.

const id = gooeyToast('Uploading...', {
  icon: <SpinnerIcon />,
})

// Later, update the toast
gooeyToast.update(id, {
  title: 'Upload complete',
  type: 'success',
  description: '3 files uploaded.',
  icon: null, // clears the custom icon
})

GooeyToastUpdateOptions:

OptionTypeDescription
titlestringNew title text
descriptionReactNodeNew body content
typeGooeyToastTypeChange the toast type/color
actionGooeyToastActionNew action button
iconReactNode | nullCustom icon (pass null to clear)

gooeyToast.dismiss(idOrFilter?)

Dismiss a single toast by ID, all toasts of a given type, or all toasts at once.

// Dismiss a specific toast
gooeyToast.dismiss(toastId)

// Dismiss all error toasts
gooeyToast.dismiss({ type: 'error' })

// Dismiss multiple types
gooeyToast.dismiss({ type: ['error', 'warning'] })

// Dismiss all toasts
gooeyToast.dismiss()

GooeyToastOptions

Options passed as the second argument to gooeyToast() and type-specific methods.

OptionTypeDescription
descriptionReactNodeBody content (string or component)
actionGooeyToastActionAction button configuration
iconReactNodeCustom icon override
durationnumberDisplay duration in ms
idstring | numberUnique toast identifier
classNamesGooeyToastClassNamesCSS class overrides
fillColorstringBackground color of the blob
borderColorstringBorder color of the blob
borderWidthnumberBorder width in px (default 1.5)
timingGooeyToastTimingsAnimation timing overrides
springbooleanEnable spring/bounce animations (default true)
bouncenumberSpring intensity from 0.05 (subtle) to 0.8 (dramatic), default 0.4
showTimestampbooleanShow/hide timestamp in toast header/body (default true)
showProgressbooleanShow countdown progress bar
onDismiss(id) => voidCalled when toast is dismissed (any reason)
onAutoClose(id) => voidCalled only on timer-based auto-dismiss
presetAnimationPresetNameAnimation preset ('smooth', 'bouncy', 'subtle', 'snappy')

GooeyToastAction

PropertyTypeRequiredDescription
labelstringYesButton text
onClick() => voidYesClick handler
successLabelstringNoLabel shown after click (morphs back to pill)

GooeyToastTimings

Fine-tune animation speeds per toast.

PropertyTypeDefaultDescription
displayDurationnumber4000Milliseconds toast stays expanded

GooeyToastClassNames

Override styles for any part of the toast.

KeyTarget
wrapperOuter container
contentContent area
headerIcon + title row
titleTitle text
iconIcon wrapper
descriptionBody text
actionWrapperButton container
actionButtonAction button

GooeyToasterProps

Props for the <GooeyToaster /> component.

PropTypeDefaultDescription
position'top-left' | 'top-center' | 'top-right' | 'bottom-left' | 'bottom-center' | 'bottom-right''bottom-right'Toast position
durationnumber--Default display duration in ms
gapnumber14Gap between stacked toasts (px)
offsetnumber | string'24px'Distance from screen edge
theme'light' | 'dark''light'Color theme
toastOptionsPartial<ExternalToast>--Default options passed to Sonner
springbooleantrueEnable spring/bounce animations globally
bouncenumber0.4Spring intensity: 0.05 (subtle) to 0.8 (dramatic)
presetAnimationPresetName--Animation preset for all toasts
closeOnEscapebooleantrueDismiss most recent toast on Escape key
closeButtonboolean | 'top-left' | 'top-right'falseShow close button on hover
showProgressbooleanfalseShow countdown progress bar on all toasts
maxQueuenumberInfinityMaximum queued toasts
queueOverflow'drop-oldest' | 'drop-newest''drop-oldest'Queue overflow strategy
dir'ltr' | 'rtl''ltr'Layout direction
swipeToDismissbooleantrueEnable swipe-to-dismiss on mobile
showTimestampbooleantrueShow/hide timestamp on all toasts globally

GooeyPromiseData<T>

Configuration for gooeyToast.promise().

PropertyTypeRequiredDescription
loadingstringYesTitle shown during loading
successstring | ((data: T) => string)YesTitle on success (static or derived from result)
errorstring | ((error: unknown) => string)YesTitle on error (static or derived from error)
descriptionobjectNoPer-phase descriptions (see below)
actionobjectNoPer-phase action buttons (see below)
classNamesGooeyToastClassNamesNoCSS class overrides
fillColorstringNoBackground color of the blob
borderColorstringNoBorder color of the blob
borderWidthnumberNoBorder width in px
timingGooeyToastTimingsNoAnimation timing overrides
springbooleanNoEnable spring/bounce animations (default true)
bouncenumberNoSpring intensity: 0.05 (subtle) to 0.8 (dramatic), default 0.4
onDismiss(id: string | number) => voidNoCalled when toast is dismissed (any reason)
onAutoClose(id: string | number) => voidNoCalled only on timer-based auto-dismiss

description sub-fields:

KeyType
loadingReactNode
successReactNode | ((data: T) => ReactNode)
errorReactNode | ((error: unknown) => ReactNode)

action sub-fields:

KeyType
successGooeyToastAction
errorGooeyToastAction

Usage Examples

Description

gooeyToast.error('Payment failed', {
  description: 'Your card was declined. Please try again.',
})

Custom React Component as Description

gooeyToast.success('Deployment complete', {
  description: (
    <div style={{ display: 'flex', flexDirection: 'column', gap: 10 }}>
      <div>
        <span>Environment:</span> <strong>Production</strong>
      </div>
      <div>
        <span>Branch:</span> <strong>main @ 3f8a2c1</strong>
      </div>
    </div>
  ),
})

Action Button with Success Label

gooeyToast.info('Share link ready', {
  description: 'Your link has been generated.',
  action: {
    label: 'Copy to Clipboard',
    onClick: () => navigator.clipboard.writeText(url),
    successLabel: 'Copied!',
  },
})

Promise Toast

gooeyToast.promise(saveData(), {
  loading: 'Saving...',
  success: 'Changes saved',
  error: 'Something went wrong',
  description: {
    success: 'All changes have been synced.',
    error: 'Please try again later.',
  },
  action: {
    error: {
      label: 'Retry',
      onClick: () => retry(),
    },
  },
})

Custom Styling

gooeyToast.success('Styled!', {
  fillColor: '#1a1a2e',
  borderColor: '#333',
  borderWidth: 2,
  classNames: {
    wrapper: 'my-wrapper',
    title: 'my-title',
    description: 'my-desc',
    actionButton: 'my-btn',
  },
})

Display Duration

gooeyToast.success('Saved', {
  description: 'Your changes have been synced.',
  timing: { displayDuration: 5000 },
})

Disabling Spring Animations

Disable bounce/spring animations for a cleaner, more subtle look:

// Per-toast: disable spring for this toast only
gooeyToast.success('Saved', {
  description: 'Your changes have been synced.',
  spring: false,
})

// Globally: disable spring for all toasts
<GooeyToaster spring={false} />

When spring is false, all spring-based animations (landing squish, blob squish, morph transitions, pill resize, header squish) use smooth ease-in-out curves instead. Error shake animations still work regardless of this setting.

Bounce Intensity

Control how dramatic the spring effect feels with a single bounce value:

// Subtle, barely-there spring
gooeyToast.success('Saved', { bounce: 0.1 })

// Default feel
gooeyToast.success('Saved', { bounce: 0.4 })

// Jelly mode
gooeyToast.success('Saved', { bounce: 0.8 })

// Set globally via GooeyToaster
<GooeyToaster bounce={0.6} />

The bounce value (0.05 to 0.8) controls spring stiffness, damping, and squish magnitude together so you get a consistent feel from one number.

Dark Mode

<GooeyToaster theme="dark" />

RTL Support

<GooeyToaster dir="rtl" />

Animation Presets

Four built-in presets: smooth, bouncy, subtle, snappy. Apply per-toast or globally:

gooeyToast.success('Saved', { preset: 'bouncy' })

// Or globally
<GooeyToaster preset="smooth" />

Progress Bar

Show a countdown progress bar on toasts:

gooeyToast.success('Saved', { showProgress: true })

// Or enable globally
<GooeyToaster showProgress />

Keyboard Shortcuts

Press Escape to dismiss the most recent toast. Enabled by default; disable with closeOnEscape={false}.

Swipe to Dismiss

On mobile, swipe toasts to dismiss them. Enabled by default; disable with swipeToDismiss={false}.

Close Button

Show a close button on hover. Position it top-left (default) or top-right:

<GooeyToaster closeButton />
<GooeyToaster closeButton="top-left" />
<GooeyToaster closeButton="top-right" />

The close button inherits the toast's border and fill color styling. Hidden during the loading phase of promise toasts.

Hiding Timestamps

// Per-toast: hide timestamp for this toast only
gooeyToast.success('Saved', { showTimestamp: false })

// Globally: hide timestamp for all toasts
<GooeyToaster showTimestamp={false} />

Exports

// Components
export { GooeyToaster } from 'goey-toast'

// Toast function
export { gooeyToast } from 'goey-toast'

// Animation presets
export { animationPresets } from 'goey-toast'

// Types
export type {
  GooeyToastOptions,
  GooeyPromiseData,
  GooeyToasterProps,
  GooeyToastAction,
  GooeyToastClassNames,
  GooeyToastTimings,
  GooeyToastUpdateOptions,
  DismissFilter,
  AnimationPreset,
  AnimationPresetName,
} from 'goey-toast'

Browser Support

goey-toast works in all modern browsers that support:

  • CSS Modules
  • SVG path animations
  • ResizeObserver
  • framer-motion (Chrome, Firefox, Safari, Edge)

See Also

License

MIT