Skip to content

@vibe-labs/design-vue-toasts

Vue 3 toast notification system for the Vibe Design System. Imperative API with variant shortcuts, promise support, pause-on-hover, and stack/queue display modes.

Installation

ts
import { toast, VibeToastContainer } from "@vibe-labs/design-vue-toasts";

Requires the CSS layer from @vibe-labs/design-components-toasts.

Setup

Add the container once at the root of your app:

vue
<!-- App.vue -->
<template>
  <RouterView />
  <VibeToastContainer position="top-right" />
</template>

Then fire toasts from anywhere — no provide/inject needed:

ts
import { toast } from "@vibe-labs/design-vue-toasts";

toast("Hello world");
toast.success("Saved successfully");

Imperative API

Basic Usage

ts
// String shorthand
toast("Something happened");

// Full options
toast({
  title: "File uploaded",
  description: "report.pdf was uploaded successfully",
  variant: "success",
  duration: 3000,
});

Variant Shortcuts

ts
toast.success("Changes saved");
toast.warning("Low disk space");
toast.danger("Failed to connect");
toast.info("New version available");

// With full options
toast.success({
  title: "Order placed",
  description: "You'll receive a confirmation email shortly",
});

Promise Toast

Shows a loading toast, awaits the promise, then updates in-place to success or error:

ts
toast.promise(
  fetch("/api/data").then((r) => r.json()),
  {
    loading: "Fetching data…",
    success: "Data loaded",
    error: "Failed to load data",
  },
);

// Dynamic messages from result/error
toast.promise(saveOrder(order), {
  loading: { title: "Saving order…", description: "Please wait" },
  success: (data) => ({ title: "Order saved", description: `Order #${data.id}` }),
  error: (err) => ({ title: "Save failed", description: err.message }),
});

The promise is returned so you can chain off it:

ts
const result = await toast.promise(fetchData(), {
  loading: "Loading…",
  success: "Done",
  error: "Failed",
});

Actions

ts
toast({
  title: "Message archived",
  actions: [
    {
      label: "Undo",
      onClick: (dismiss) => {
        undoArchive();
        dismiss();
      },
    },
  ],
});

Manage Toasts

ts
// Dismiss by ID
const t = toast("Processing…");
toast.dismiss(t.id);

// Dismiss all
toast.dismissAll();

// Update in-place
const t = toast({ title: "Uploading…", duration: 0 });
toast.update(t.id, {
  title: "Upload complete",
  variant: "success",
  duration: 3000,
});

Persistent Toast

ts
toast({
  title: "Action required",
  duration: 0, // never auto-dismiss
  closable: true, // user can still close manually
});

Custom Render

ts
toast({
  render: ({ toast, dismiss }) => h(MyCustomToast, { toast, onClose: dismiss }),
});

Components

VibeToastContainer

Teleports to <body> and renders visible toasts. Add once at your app root.

vue
<!-- Default -->
<VibeToastContainer />

<!-- Customised -->
<VibeToastContainer position="bottom-center" :limit="3" mode="queue" :pause-on-hover="true" :default-duration="4000" />

<!-- Custom icon slot (applied to all toasts) -->
<VibeToastContainer>
  <template #icon="{ variant }">
    <SuccessIcon v-if="variant === 'success'" />
    <ErrorIcon v-if="variant === 'danger'" />
    <InfoIcon v-if="variant === 'info'" />
    <WarningIcon v-if="variant === 'warning'" />
  </template>
</VibeToastContainer>

Props

PropTypeDefaultDescription
positionToastContainerPosition"top-right"Screen position
limitnumber5Max visible toasts (stack mode)
modeToastDisplayMode"stack"stack (all visible) or queue (one at a time)
pauseOnHoverbooleantruePause auto-dismiss on hover
defaultDurationnumber5000Default auto-dismiss duration (ms)

Display Modes

ModeBehaviour
stackAll toasts visible simultaneously (up to limit), stacked vertically
queueOne toast at a time; next shows after current dismisses

VibeToast

Individual toast component. Rendered internally by the container — you shouldn't need to use this directly.

Features: enter/exit animations with reduced-motion fallback, pause-on-hover timer that resumes where it left off, custom render function support.

Composable

useToast()

Returns the toast API and the reactive toast list. Used internally by VibeToastContainer.

ts
import { useToast } from "@vibe-labs/design-vue-toasts";

const { toast, toasts, dismiss, dismissAll, update } = useToast();

Toast Options

ts
interface ToastOptions {
  title?: string;
  description?: string;
  variant?: ToastVariant; // success · warning · danger · info
  duration?: number; // ms, 0 = persistent. Default 5000
  closable?: boolean; // Default true
  actions?: ToastAction[];
  class?: string;
  id?: string; // auto-generated if omitted
  render?: (ctx) => VNode; // custom render function
}

Architecture

The toast system uses a singleton reactive store — a single ref<ToastInstance[]> shared across all consumers. No provide/inject needed, which means you can fire toasts from Pinia actions, API interceptors, route guards, or anywhere else outside the component tree.

Dependencies

PackagePurpose
@vibe-labs/design-components-toastsCSS tokens + generated styles

Build

bash
npm run build

Built with Vite + vite-plugin-dts. Outputs ES module with TypeScript declarations.