vue-sonner

An opinionated, customizable toast notification component for Vue 3 and Nuxt, ported from the React library Sonner.

Library
npm
v2.0.9
1,461stars
MIT License

Repository Health

Pre-computed score based on development activity, maintenance, community, maturity, and trend momentum.How we score it →
48/100Fair
Development Activity0
Maintenance44
Community56
Maturity52
Momentum40

Technical Analysis

AI-assessed by reading the actual repository — architecture, code quality, innovation, and documentation.How we score it →
64/100Good
Architecture80
Code Quality65
Innovation55
Learning Curve55

Vue Sonner is a direct Vue port of the popular React toast library Sonner. It ships a single <Toaster /> component plus an imperative toast() API — toast.success(), toast.error(), toast.promise(), toast.custom() — so any component in a Vue 3 or Nuxt app can trigger a toast without prop drilling or a manual store.

Under the hood, a framework-agnostic Observer/pub-sub store holds the toast queue, and a useVueSonner() composable bridges it into Vue’s reactivity system. The library ships with sensible default styling (positions, themes, swipe-to-dismiss, stacking/expand behavior) but is fully overridable via an unstyled prop and a granular classes object, making it easy to restyle with Tailwind or a custom design system. A dedicated vue-sonner/nuxt module auto-registers the component and a $toast plugin for Nuxt 3/4 projects.

What You Get

  • A <Toaster /> component and imperative toast() API (toast.success, .error, .warning, .info, .loading, .promise, .custom, .dismiss) usable from any component
  • Promise-aware toasts that automatically transition through loading → success/error states based on the resolved value or thrown error
  • Swipe-to-dismiss gestures with configurable swipeDirections per toast position, plus stacked/expand toast layout
  • A first-class vue-sonner/nuxt module that auto-registers Toaster and injects a $toast plugin, with optional CSS opt-out
  • Full styling control via unstyled mode and a per-part classes object (toast, title, description, action/cancel/close buttons) for Tailwind or custom design systems
  • TypeScript types for every public shape (ToastT, ToasterProps, ExternalToast, etc.) shipped alongside the compiled library

Common Use Cases

  • Showing loading → success/error feedback for an async form submission or API call via toast.promise()
  • Registering the Nuxt module once and calling the injected $toast helper from any page or component in a Nuxt 3/4 app
  • Restyling toasts to match an existing Tailwind design system using the unstyled prop and classes object instead of overriding default CSS
  • Showing an undo action toast (with an action button and callback) after a destructive operation like delete or archive

Under The Hood

Architecture A central singleton Observer (src/packages/state.ts) maintains a subscriber list and toast array, framework-agnostic of Vue itself; the exported toast() function and its namespaced methods (success, error, promise, custom, dismiss, …) all funnel through this store. useVueSonner() (src/packages/hooks.ts) subscribes to the store inside a watchEffect and reconciles updates into a reactive activeToasts ref via nextTick, bridging the plain-JS store into Vue’s reactivity. Toaster.vue renders and groups active toasts by position and delegates per-toast presentation, swipe handling, and height measurement to Toast.vue. The Nuxt integration (src/module.ts, src/runtime/plugin.ts) is a thin wrapper: defineNuxtModule registers Toaster client-only and injects a $toast plugin, with an option to opt out of the shipped CSS — a clean separation between a framework-agnostic core store and Vue/Nuxt-specific presentation and wiring.

Tech Stack Written in TypeScript against Vue 3.5 as a peer dependency, built with tsdown (a Rolldown-based bundler) for the primary ESM library output plus a separate UMD build (tsdown.config.umd.ts) for CDN/<script> usage. The Nuxt module is built separately via @nuxt/module-builder/@nuxt/kit. The repo is a pnpm workspace with the library, a Vite+UnoCSS demo/docs app, and a separate test/ Playwright workspace as distinct members. The published package has no runtime dependencies beyond Vue itself.

Code Quality End-to-end tests live in a separate test/ Vite+Vue workspace driven by Playwright (test/e2e/vue.spec.ts, run via pnpm test:e2e --ui), but there are no unit tests for the core state.ts/hooks.ts logic in isolation. Every public shape (ToastT, ToasterProps, ExternalToast, etc.) has an explicit TypeScript interface, and the promise-toast flow in state.ts distinguishes HTTP-response failures, thrown Errors, and custom error callbacks with dedicated handling rather than swallowing errors. Two GitHub Actions workflows run on every push, but both only execute pnpm build:lib (plus a preview-package publish step) — neither runs the Playwright suite, so CI verifies the library still builds, not that its swipe/animation behavior still passes its own tests.

What Makes It Unique Rather than designing a new toast model, Vue Sonner’s contribution is a faithful, idiomatic port of the React sonner library’s observer/pub-sub design and toast-type API surface into Vue’s Composition API, plus a genuine first-class Nuxt module (auto-registered component, client-only plugin, CSS opt-out) that its React counterpart has no equivalent for. It’s a solid adaptation layer rather than a novel toast-notification design.

Join founders buildingwith open source

Opinionated takes, migration guides, cost-saving tips, and insights from the open source ecosystem.

Subscribe on Substack
Join 750+ subscribers

Search