📰 Featured in JavaScript Weekly · 🔥 Trending on Reddit (/r/vuejs)
Framework-agnostic toast engine with a Vue 3 renderer. Typed core, smooth stack animations, CSS-first theming, and full control over layout and behavior.
Playground · Usage · Configuration
Table of Contents
Toastflow is a headless toast engine with a Vue 3 renderer. It keeps toast state in a tiny framework-agnostic store so you can render it your way while keeping predictable behaviors.
- Deterministic rules for duplicates, timers, pause-on-hover, close-on-click, and clear-all.
- CSS-first theming: swap the look by editing a handful of variables.
- Works inside components or in plain TS/JS modules and services.
- Headless slot to render your own card while reusing the store logic.
- toastflow-core: typed, framework-agnostic toast store.
- vue-toastflow: Vue 3 renderer with
<ToastContainer />, a globaltoasthelper, defaults, and icons. - playground-vue: Vite + Vue demo playground for manual testing.
pnpm add vue-toastflow
# npm i vue-toastflow
# yarn add vue-toastflow
# bun i vue-toastflow// main.ts
import {createApp} from "vue";
import App from "./App.vue";
import {createToastflow, ToastContainer} from "vue-toastflow";
const app = createApp(App);
app.use(
createToastflow({
// optional global defaults
position: "top-right",
duration: 5000,
}),
);
// register globally or import locally where you render it
app.component("ToastContainer", ToastContainer);
// call toast.* only after the plugin is installed
app.mount("#app");Render a container and fire toasts anywhere:
<!-- App.vue -->
<template>
<ToastContainer/>
<RouterView/>
</template>import {toast} from "vue-toastflow";
toast.success({title: "Saved", description: "Your changes are live."});
toast.warning({description: "Low balance"});
const id = toast.error({title: "Oops", description: "Check console."});
toast.update(id, {description: "Fixed. All good now."});
toast.dismiss(id);const run = toast.loading(
() => fetch("/api/save").then((r) => r.json()),
{
loading: {title: "Saving", description: "Hang tight."},
success: (data) => ({
title: "Saved",
description: `Stored item ${data.id}.`,
}),
error: (err) => ({
title: "Error",
description: err instanceof Error ? err.message : "Please try again.",
}),
},
);
await run;
console.log(run.toastId);toast.info({
title: "<strong>New version</strong>",
description: "Release notes are <a href='/changelog'>here</a>.",
supportHtml: true,
});<ToastContainer
v-slot="{
toast,
dismiss,
bumpAnimationClass,
clearAllAnimationClass,
updateAnimationClass,
}"
>
<div
class="my-toast"
:class="[
toast.type,
bumpAnimationClass,
toast.phase === 'clear-all' && clearAllAnimationClass,
updateAnimationClass
]"
@click="toast.closeOnClick && dismiss(toast.id)"
>
<header>
<strong>{{ toast.title }}</strong>
<button @click.stop="dismiss(toast.id)">x</button>
</header>
<p v-if="toast.description">{{ toast.description }}</p>
<small v-if="toast.showCreatedAt">
Sent at {{ toast.createdAtFormatter(toast.createdAt) }}
</small>
</div>
</ToastContainer>Pass any types.ts fields to createToastflow; per-toast options override them:
position: "top-right" (default), "top-left", "top-center", "bottom-*"duration:5000ms by default;Infinityor0disables auto-dismiss (progress bar auto-hides when disabled)maxVisible:5per stack; eviction respectsorderorder: "newest" (default) or "oldest" per stackpreventDuplicates:falseby default; matches by position + type + title + descriptionprogressBar,pauseOnHover,pauseStrategy("resume" | "reset")animation: class names for enter/leave/move (name), bump, clearAll, update (defaults useToastflow__*)closeButton(true),closeOnClick(false)offset(16px),gap(8px),width(350px),zIndex(9999)supportHtml:false(opt-in)showCreatedAtandcreatedAtFormatterfor timestamps- lifecycle hooks:
onMount,onUnmount,onClick,onClose
- CSS variables live in styles.css and are auto-imported with the Vue package.
- Key
variables:
--tf-toast-bg,--tf-toast-color,--tf-toast-border-color,--tf-toast-radius,--tf-toast-padding,--tf-toast-icon-size,--tf-toast-progress-height, plus per-type colors like--success-bgand--error-text. - Animations are pure CSS class names; override them via the
animationconfig or by redefining theToastflow__*keyframes. Animations are implemented using TransitionGroup.
toast.subscribeEvents(listener)getsduplicate,timer-reset, andupdateevents.toast.getState()returns the current snapshot; helper methods:toast.show,toast.success,toast.error,toast.warning,toast.info,toast.loading,toast.update,toast.dismiss,toast.dismissAll,toast.pause,toast.resume,toast.getConfig.
MIT - see LICENSE.

