Skip to content

feat(VSnackbarQueue): show multiple snackbars#22605

Merged
J-Sek merged 33 commits intonextfrom
feature/VSnackbarQueue-total-visible
Feb 10, 2026
Merged

feat(VSnackbarQueue): show multiple snackbars#22605
J-Sek merged 33 commits intonextfrom
feature/VSnackbarQueue-total-visible

Conversation

@J-Sek
Copy link
Copy Markdown
Contributor

@J-Sek J-Sek commented Feb 7, 2026

Description

resolves #21927

VSnackbarQueue overhaul inspired by VueSonner

  • total-visible to show multiple snackbars
    • handles variable height
    • collapsing (good enough, meant only for uniform toasts)
    • overflow mode (holding queued items by default)
    • exposing clear
    • each posted item can include onDismissed callback
  • VSnackbar improvements:
    • pauses countdown when tab is not visible and on focus within
    • title prop on class and variable for customizing title
    • prepend slot + props for icon, avatar and loading animation
    • reverse-timer prop
    • timer="bottom" support
    • support for deferred item resolution (promises)
    • support transition with "scroll-auto" or "slide-auto" that is resolved based on the location

Docs:

  • reworked examples
  • migration guide

Markup:

<template>
  <v-app theme="dark">
    <v-snackbar-queue
      ref="queue"
      v-model="messages"
      gap="12"
      location="top end"
      max-width="400"
      timer-color="on-surface"
      total-visible="4"
      transition="slide-auto"
      closable
      collapsed
      timer
    >
      <template #header="{ item }">
        <div v-if="item.header" class="d-flex text-body-small pa-3 pb-0">
          <div class="text-uppercase">{{ item.header.provider }}</div>
          <v-spacer />
          <div>{{ item.header.when }}</div>
        </div>
      </template>
      <template #actions="{ item, props }">
        <v-icon-btn
          v-if="!item.vertical"
          aria-label="Close"
          icon="$close"
          variant="text"
          v-bind="props"
        />
        <v-btn
          v-else
          text="Close"
          variant="text"
          v-bind="props"
        />
      </template>
    </v-snackbar-queue>
    <v-container class="d-flex ga-3 justify-center">
      <v-btn
        text="Promise"
        @click="simulateTask"
      />
      <v-btn
        text="Clear"
        @click="queue?.clear()"
      />
    </v-container>
  </v-app>
</template>

<script setup lang="ts">
  import { onBeforeUnmount, onMounted, ref, useTemplateRef } from 'vue'
  import { SnackbarQueueMessage } from '@/types'
  import type { VSnackbarQueue } from '@/components/VSnackbarQueue'

  const messages = ref<SnackbarQueueMessage[]>([])
  const queue = useTemplateRef<VSnackbarQueue>('queue')

  onMounted(() => {
    setTimeout(() => {
      messages.value.push({
        title: 'Notice',
        text: 'Inbox check... please wait.',
        color: 'info',
        loading: true,
      })
    }, 300)
    setTimeout(() => {
      messages.value.push({
        prependIcon: 'mdi-inbox-arrow-down',
        title: 'Inbox',
        text: 'You have 3 new messages in your Inbox. Click here to review them before they expire.',
        color: 'primary',
        vertical: true,
      })
    }, 700)
    setTimeout(() => {
      messages.value.push({
        prependIcon: '$complete',
        title: 'Done',
        text: 'Task submitted.',
        color: 'success',
      })
    }, 1200)
    setTimeout(() => {
      messages.value.push({
        title: 'Session Warning',
        text: 'Your session will expire in 5 minutes. Please save any unsaved changes to avoid losing your work.',
        color: 'warning',
        vertical: true,
        timeout: 2000,
      })
    }, 1700)
    setTimeout(() => {
      messages.value.push({
        prependIcon: '$error',
        text: 'Task failed successfully.',
        color: 'error',
        timeout: -1,
      })
    }, 2200)
    setTimeout(() => {
      messages.value.push({
        header: {
          provider: 'Signal',
          when: '2 min ago',
        },
        prependAvatar: 'https://cdn.vuetifyjs.com/images/lists/5.jpg',
        title: '@marley4122',
        text: 'The reproduction is missing. Would you...',
        timeout: -1,
      })
    }, 2600)
  })

  onBeforeUnmount(() => {
    messages.value = []
  })

  let attempt = 0

  function simulateTask () {
    const uploadPromise = new Promise((resolve, reject) =>
      setTimeout(() => {
        attempt++ % 2
          ? resolve('2 files uploaded')
          : reject(new Error('Server not reachable'))
      }, 3000)
    )

    messages.value.push({
      text: 'Loading...',
      promise: uploadPromise,
      success: (data: any) => ({
        prependIcon: '$complete',
        title: 'success',
        text: data,
        color: 'success',
        timer: true,
      }),
      error: (data?: Error) => ({
        prependIcon: '$error',
        title: 'Error',
        text: `Operation failed: ${data?.message}`,
        color: 'error',
        closable: true,
        timeout: -1,
      }),
    })
  }
</script>

<style>
.v-snackbar__wrapper {
  &[class*="-transition-enter-active"],
  &[class*="-transition-leave-active"] {
    transition-duration: .5s;
    transition-timing-function: cubic-bezier(0.34, 1.56, 0.64, 1);
  }
  &.slide-x-transition-enter-from,
  &.slide-x-transition-leave-to {
    transform: translateX(-30%);
  }
  &.slide-x-reverse-transition-enter-from,
  &.slide-x-reverse-transition-leave-to {
    transform: translateX(30%);
  }
}
</style>

@J-Sek J-Sek marked this pull request as ready for review February 8, 2026 20:30
@J-Sek J-Sek self-assigned this Feb 8, 2026
@J-Sek J-Sek requested a review from a team February 8, 2026 21:31
@J-Sek J-Sek linked an issue Feb 8, 2026 that may be closed by this pull request
@J-Sek J-Sek merged commit 7248d20 into next Feb 10, 2026
16 checks passed
@J-Sek J-Sek deleted the feature/VSnackbarQueue-total-visible branch February 10, 2026 05:00
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Feature Request] Toast or Stacked VSnackbar

1 participant