Appearance
@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
| Prop | Type | Default | Description |
|---|---|---|---|
position | ToastContainerPosition | "top-right" | Screen position |
limit | number | 5 | Max visible toasts (stack mode) |
mode | ToastDisplayMode | "stack" | stack (all visible) or queue (one at a time) |
pauseOnHover | boolean | true | Pause auto-dismiss on hover |
defaultDuration | number | 5000 | Default auto-dismiss duration (ms) |
Display Modes
| Mode | Behaviour |
|---|---|
stack | All toasts visible simultaneously (up to limit), stacked vertically |
queue | One 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
| Package | Purpose |
|---|---|
@vibe-labs/design-components-toasts | CSS tokens + generated styles |
Build
bash
npm run buildBuilt with Vite + vite-plugin-dts. Outputs ES module with TypeScript declarations.