Advanced Examples

Advanced patterns and complex use cases for Nuxt Notify.

Queue Management

Sequential Notifications

Show notifications one after another:

vue
<script setup>
const toast = useToast();

async function processQueue() {
  const steps = [
    { title: "Initializing", description: "Preparing data..." },
    { title: "Processing", description: "Analyzing files..." },
    { title: "Finalizing", description: "Saving results..." },
    { title: "Complete", description: "All done!" },
  ];

  for (let i = 0; i < steps.length; i++) {
    await new Promise((resolve) => setTimeout(resolve, 2000));

    const isLast = i === steps.length - 1;

    toast.add({
      type: isLast ? "success" : "info",
      title: steps[i].title,
      description: steps[i].description,
      showProgress: true,
      duration: 3000,
    });
  }
}
</script>

Batch Operations

Handle multiple operations with progress:

vue
<script setup>
const toast = useToast();

async function batchDelete(items) {
  let completed = 0;
  let failed = 0;
  const total = items.length;

  // Show initial progress
  const progressToast = toast.info(
    "Deleting Items",
    `Processing 0 of ${total}...`,
    { duration: Infinity, showProgress: false }
  );

  for (const item of items) {
    try {
      await api.delete(item.id);
      completed++;
    } catch (error) {
      failed++;
    }

    // Update progress (in real app, you'd update the existing toast)
    if (completed + failed < total) {
      toast.info(
        "Deleting Items",
        `Processing ${completed + failed} of ${total}...`,
        { duration: Infinity }
      );
    }
  }

  // Show final result
  toast.clear();

  if (failed === 0) {
    toast.success(
      "Batch Delete Complete",
      `${completed} items deleted successfully`
    );
  } else {
    toast.warning(
      "Batch Delete Complete",
      `${completed} succeeded, ${failed} failed`,
      {
        actions: [
          { label: "View Errors", onClick: () => showErrors() },
          { label: "Retry Failed", onClick: () => retryFailed() },
        ],
      }
    );
  }
}
</script>

Real-Time Updates

Live Notifications

Handle real-time events:

vue
<script setup>
const toast = useToast();

// WebSocket or SSE connection
const ws = useWebSocket("wss://api.example.com/notifications");

ws.onMessage((event) => {
  const notification = JSON.parse(event.data);

  switch (notification.type) {
    case "mention":
      toast.add({
        type: "info",
        title: `${notification.user.name} mentioned you`,
        description: notification.message,
        avatar: {
          type: "image",
          src: notification.user.avatar,
        },
        actions: [
          { label: "Reply", onClick: () => handleReply(notification.id) },
          { label: "View", onClick: () => navigateTo(notification.url) },
        ],
      });
      break;

    case "task_assigned":
      toast.warning("New Task Assigned", notification.task.title, {
        showProgress: true,
        actions: [
          { label: "View Task", onClick: () => openTask(notification.task.id) },
        ],
      });
      break;

    case "update":
      toast.success(notification.title, notification.message);
      break;
  }
});
</script>

Status Updates

Track ongoing operations:

vue
<script setup>
const toast = useToast();
const operationStatus = ref("idle");

async function longRunningOperation() {
  operationStatus.value = "starting";

  toast.info("Starting Process", "Initializing...", {
    showProgress: true,
    duration: 5000,
  });

  try {
    // Step 1
    operationStatus.value = "step1";
    await performStep1();
    toast.info("Progress Update", "Step 1 complete", { duration: 2000 });

    // Step 2
    operationStatus.value = "step2";
    await performStep2();
    toast.info("Progress Update", "Step 2 complete", { duration: 2000 });

    // Step 3
    operationStatus.value = "step3";
    await performStep3();
    toast.success("Process Complete", "All steps finished successfully");

    operationStatus.value = "complete";
  } catch (error) {
    operationStatus.value = "error";
    toast.error("Process Failed", error.message);
  }
}
</script>

Undo/Redo Pattern

Undo Delete

Implement undo functionality:

vue
<script setup>
const toast = useToast();
const deletedItems = ref([]);

function deleteItem(item) {
  // Store item for potential undo
  deletedItems.value.push(item);

  // Soft delete
  item.deleted = true;

  toast.add({
    type: "success",
    title: "Item Deleted",
    description: item.name,
    duration: 5000,
    actions: [
      {
        label: "Undo",
        onClick: () => {
          // Restore item
          item.deleted = false;
          deletedItems.value = deletedItems.value.filter(
            (i) => i.id !== item.id
          );
          toast.info("Restored", `${item.name} has been restored`);
        },
      },
    ],
  });

  // Permanently delete after 5 seconds
  setTimeout(() => {
    if (item.deleted) {
      api.permanentlyDelete(item.id);
      deletedItems.value = deletedItems.value.filter((i) => i.id !== item.id);
    }
  }, 5000);
}
</script>

Bulk Undo

Undo multiple operations:

vue
<script setup>
const toast = useToast();
const operationHistory = ref([]);

function bulkDelete(items) {
  const operation = {
    type: "bulk_delete",
    items: items,
    timestamp: Date.now(),
  };

  operationHistory.value.push(operation);

  // Perform deletion
  items.forEach((item) => (item.deleted = true));

  toast.warning("Bulk Delete", `${items.length} items deleted`, {
    actions: [
      {
        label: "Undo All",
        onClick: () => {
          items.forEach((item) => (item.deleted = false));
          operationHistory.value = operationHistory.value.filter(
            (op) => op !== operation
          );
          toast.success("Restored", `${items.length} items restored`);
        },
      },
    ],
    duration: 10000,
  });
}
</script>

Context-Aware Notifications

Position Based on Context

Change position based on UI context:

vue
<script setup>
const toast = useToast();
const route = useRoute();

function showContextualToast(message) {
  // Different positions for different pages
  const positions = {
    "/dashboard": "top-right",
    "/editor": "bottom-right", // Don't block editor toolbar
    "/chat": "top-center", // Centered for chat
    "/settings": "top-left",
  };

  const position = positions[route.path] || "top-right";

  toast.success(message.title, message.description, {
    position,
    duration: 3000,
  });
}
</script>

Conditional Formatting

Style based on conditions:

vue
<script setup>
const toast = useToast();

function notifyUser(notification) {
  const isUrgent = notification.priority === "high";
  const isFromAdmin = notification.sender.role === "admin";

  toast.add({
    type: isUrgent ? "warning" : "info",
    title: notification.title,
    description: notification.message,
    duration: isUrgent ? 10000 : 5000,
    showProgress: isUrgent,
    avatar: notification.sender.avatar,
    ui: {
      root: isUrgent ? "ring-2 ring-amber-500" : undefined,
      title: isFromAdmin ? "font-bold text-primary-600" : undefined,
    },
    actions: isUrgent
      ? [{ label: "View Now", onClick: () => handleUrgent(notification) }]
      : undefined,
  });
}
</script>

Permission Requests

Request User Action

Ask for permissions with context:

vue
<script setup>
const toast = useToast();

function requestNotificationPermission() {
  toast.add({
    type: "info",
    title: "Enable Notifications",
    description: "Get notified about important updates and messages",
    duration: Infinity,
    icon: "i-lucide-bell",
    actions: [
      {
        label: "Enable",
        onClick: async () => {
          const permission = await Notification.requestPermission();

          if (permission === "granted") {
            toast.success(
              "Notifications Enabled",
              "You'll now receive updates"
            );
          } else {
            toast.warning(
              "Notifications Blocked",
              "You can enable them in settings"
            );
          }
        },
      },
      {
        label: "Not Now",
        onClick: () => {
          toast.clear();
          // Ask again later
          setTimeout(() => requestNotificationPermission(), 86400000); // 24 hours
        },
      },
    ],
  });
}
</script>

Multi-Step Processes

Wizard Progress

Show progress through multi-step forms:

vue
<script setup>
const toast = useToast();
const currentStep = ref(1);
const totalSteps = 5;

function completeStep(stepNumber) {
  currentStep.value = stepNumber + 1;

  if (stepNumber < totalSteps) {
    toast.success(
      `Step ${stepNumber} Complete`,
      `Progress: ${stepNumber}/${totalSteps}`,
      {
        showProgress: true,
        duration: 2000,
        position: "bottom-right",
      }
    );
  } else {
    toast.success("All Steps Complete!", "Your setup is finished", {
      actions: [
        { label: "Get Started", onClick: () => navigateTo("/dashboard") },
      ],
      duration: 5000,
    });
  }
}
</script>

Error Recovery

Retry with Exponential Backoff

Handle network errors gracefully:

vue
<script setup>
const toast = useToast();

async function retryableRequest(fn, maxRetries = 3) {
  let retries = 0;

  while (retries < maxRetries) {
    try {
      return await fn();
    } catch (error) {
      retries++;

      if (retries < maxRetries) {
        const delay = Math.pow(2, retries) * 1000;

        toast.warning(
          "Request Failed",
          `Retrying in ${delay / 1000} seconds... (${retries}/${maxRetries})`,
          {
            showProgress: true,
            duration: delay,
            actions: [
              {
                label: "Cancel",
                onClick: () => {
                  throw new Error("Cancelled by user");
                },
              },
            ],
          }
        );

        await new Promise((resolve) => setTimeout(resolve, delay));
      } else {
        toast.error(
          "Request Failed",
          "Maximum retries reached. Please try again later.",
          {
            actions: [
              {
                label: "Retry Now",
                onClick: () => retryableRequest(fn, maxRetries),
              },
            ],
          }
        );
        throw error;
      }
    }
  }
}
</script>