Framework-Agnostic Toast Engine for Vue – Toastflow

Install & Download:

# Yarn
$ yarn add vue-toastflow
# NPM
$ npm install vue-toastflow
# PNPM
$ pnpm install vue-toastflow

Description:

Toastflow is a headless toast notification component that manages notification state through a framework-agnostic store and a Vue renderer.

It separates logic from presentation to handle stack animations, timers, and queue management with deterministic rules.

Features

  • Framework-Agnostic Store: The core logic operates independently of the UI framework to manage state.
  • CSS-First Theming: You can customize appearance by modifying specific CSS variables .
  • Headless Rendering: The component exposes a slot to render custom markup while retaining store logic.
  • Deterministic Behavior: The engine enforces strict rules for duplicates, timer pauses, and stack eviction.
  • Async Promise Handling: It updates toast states automatically based on promise resolution or rejection.
  • Interactive Buttons: You can inject action buttons directly into the notification layout.

Preview

toast-engine-toastflow

Use Cases

  • API Status Feedback: Display loading indicators that transition to success or error messages upon request completion.
  • Undo Actions: Present a temporary notification with a button to reverse a deletion or state change.
  • System-Wide Alerts: Broadcast maintenance warnings or connection errors that persist until dismissed.
  • Custom Design Systems: Implement a notification UI that strictly adheres to internal brand guidelines using headless slots.

How to Use It

1. Install the component with a package manager you prefer.

pnpm add vue-toastflow
# or
npm install vue-toastflow

2. Initialize the plugin in your main entry file. This step configures global defaults such as position and duration.

// main.ts
import { createApp } from "vue";
import App from "./App.vue";
import { createToastflow, ToastContainer } from "vue-toastflow";
const app = createApp(App);
app.use(
  createToastflow({
    position: "top-right",
    duration: 5000, // Default duration in ms
    maxVisible: 5,  // Limit the stack size
  })
);
// Register the container component globally
app.component("ToastContainer", ToastContainer);
app.mount("#app");

3. Place the ToastContainer in your root component. This component renders the active toast stack.

<!-- App.vue -->
<template>
  <ToastContainer />
  <RouterView />
</template>

4. You can then trigger notifications from any file using the toast helper.

import { toast } from "vue-toastflow";
// Simple success message
toast.success({ 
  title: "Profile Updated", 
  description: "Your changes have been saved." 
});
// Error message with an ID for manual control
const errorId = toast.error({ 
  title: "Connection Failed", 
  description: "Retrying..." 
});
// Update the existing toast later
setTimeout(() => {
  toast.update(errorId, { description: "Connection restored." });
}, 2000);

5. Toastflow tracks promise states automatically. It shows a loading state initially and switches to success or error based on the result.

const saveData = async () => {
  const request = fetch("/api/save", { method: "POST" });
  await toast.loading(
    () => request.then((res) => res.json()),
    {
      loading: { 
        title: "Saving...", 
        description: "Please wait while we process your data." 
      },
      success: (data) => ({
        title: "Success",
        description: `Record ${data.id} created successfully.`,
      }),
      error: (err) => ({
        title: "Error",
        description: err.message || "Something went wrong.",
      }),
    }
  );
};

6. You can take full control of the markup by using the scoped slot in ToastContainer. This method lets you use your own CSS classes or utility framework like Tailwind CSS.

<template>
  <ToastContainer v-slot="{ toast, dismiss }">
    <div 
      class="custom-toast" 
      :class="toast.type"
      @click="dismiss(toast.id)"
    >
      <div class="toast-header">
        <strong>{{ toast.title }}</strong>
        <button @click.stop="dismiss(toast.id)">Close</button>
      </div>
      <p>{{ toast.description }}</p>
    </div>
  </ToastContainer>
</template>

7. Available configuration options. You can pass these options to createToastflow or individual toast calls.

OptionTypeDefaultDescription
positionString"top-right"Screen position (e.g., top-left, bottom-center).
durationNumber5000Time in ms before auto-dismiss. 0 or Infinity disables it.
maxVisibleNumber5Maximum number of toasts displayed at once.
orderString"newest"Stack order strategy (newest or oldest).
preventDuplicatesBooleanfalsePrevents rendering identical toasts.
pauseOnHoverBooleantruePauses the timer when the user hovers over the toast.
closeOnClickBooleanfalseDismisses the toast when clicked.
supportHtmlBooleanfalseEnables HTML rendering in title and description.
buttonsObjectundefinedConfiguration for action buttons inside the toast.

8. API Methods:

MethodDescription
toast.show(options)Renders a generic toast.
toast.success(options)Renders a success variant.
toast.error(options)Renders an error variant.
toast.loading(promise, options)Wraps a promise with loading/success/error states.
toast.dismiss(id)Removes a specific toast by ID.
toast.dismissAll()Clears all active toasts.
toast.update(id, options)Updates the content or options of an active toast.

Related Resources

FAQs

Q: Can I use Toastflow with Nuxt?
A: Yes, Toastflow works with Nuxt.

Q: How do I customize the animations?
A: You can override the default CSS classes or provide custom class names in the animation configuration object.

Q: Does it support right-to-left (RTL) layouts?
A: The library does not enforce directionality, so you can handle RTL by applying standard CSS to the container or custom slots.

Q: Can I render HTML content inside the toast?
A: Yes, you can enable the supportHtml option to render HTML strings in the title or description fields.

Tags:

Add Comment