Skip to main content
Vuetify0 v1.0 is here
Vuetify0 Logo
Theme
Mode
Palettes
Accessibility
Vuetify One
Sign in to Vuetify One

Access premium tools across the Vuetify ecosystem — Bin, Play, Studio, and more.

Not a subscriber? See what's included

Snackbar

Headless compound component for toast and snackbar notifications. Pairs with useNotifications for queue-driven stacks with auto-dismiss and pause on hover.

Edit this page
Report a Bug
Open issues
View on GitHub
Copy Markdown

PreviewRenders elementIntermediateAug 3, 2026

Usage

A single snackbar — render directly when you control the lifecycle yourself.

<script setup lang="ts">
  import { shallowRef } from 'vue'
  import { Snackbar } from '@vuetify/v0'

  const visible = shallowRef(false)

  function onShow () {
    visible.value = true
  }

  function onDismiss () {
    visible.value = false
  }
</script>

<template>
  <div class="relative flex items-center justify-center min-h-48 p-6 bg-background rounded-lg border border-divider overflow-hidden">
    <button
      class="px-4 py-2 bg-primary text-on-primary rounded-md text-sm font-medium"
      @click="onShow"
    >
      Show Snackbar
    </button>

    <Snackbar.Portal class="absolute bottom-4 right-4" :teleport="false">
      <Snackbar.Root
        v-if="visible"
        class="flex items-center gap-3 px-4 py-2.5 rounded-lg shadow-lg text-sm bg-surface border border-divider"
        role="status"
        @dismiss="onDismiss"
      >
        <Snackbar.Content>
          Changes saved successfully
        </Snackbar.Content>

        <Snackbar.Close class="p-1 -mr-1 opacity-50 hover:opacity-100">
          <svg aria-hidden="true" class="w-4 h-4" viewBox="0 0 24 24">
            <path d="M19,6.41L17.59,5L12,10.59L6.41,5L5,6.41L10.59,12L5,17.59L6.41,19L12,13.41L17.59,19L19,17.59L13.41,12L19,6.41Z" fill="currentColor" />
          </svg>
        </Snackbar.Close>
      </Snackbar.Root>
    </Snackbar.Portal>
  </div>
</template>

Anatomy

vue
<script setup lang="ts">
  import { Snackbar } from '@vuetify/v0'
</script>

<template>
  <Snackbar.Portal>
    <Snackbar.Queue>
      <Snackbar.Root>
        <Snackbar.Content />
        <Snackbar.Close />
      </Snackbar.Root>
    </Snackbar.Queue>

    <Snackbar.Announcer />
  </Snackbar.Portal>
</template>

Examples

Toast notifications with undo

Snackbar.Queue connects to useNotifications by namespace and exposes its items newest-first through the default slot. A single ToastHost is mounted once near the root; anywhere else in the app, useToasts().notify() or remove() pushes a notification and the host renders it. Each toast auto-dismisses on the timeout passed to send, the stack pauses while hovered or focused (WCAG 2.2.1) for free, and Snackbar.Close dismisses without any @click wiring.

The undo affordance rides along on the notification’s data payload: remove() deletes a file, then sends a toast carrying data.undo — a closure that splices the file back at its original index. The host reads that closure off the ticket and renders an Undo button beside Close. Undo restores the file and calls ticket.dismiss(), which removes the toast from the display queue only, whereas Snackbar.Close inside a queue permanently unregisters the notification from both the queue and the registry. Reach for dismiss() when the item should survive in an inbox.

Reach for the queue whenever notifications flow through useNotifications; for a transient one-off message you control directly, render a Snackbar.Root without a queue (see Usage). The display surface is layout-agnostic — the stacking here is a plain flex column of consumer-styled cards, built on the createQueue primitive underneath.

FileRole
useToasts.tsOwns the notifications instance and the deletable file list; exposes notify, remove, and the undo restore closure
ToastHost.vueRenders the Snackbar.Queue surface — a stacked column of severity-styled toasts, each with a Close and a conditional Undo button
toast-host.vueDemo entry — action buttons and a file list wired to the composable, plus the mounted ToastHost
  • Q3-report.pdf
  • design-spec.fig
  • budget.xlsx

Stacked toasts

Newer toasts collapse into a peeked stack — each card offset, scaled, and faded by depth — and fan out into a full column while the pointer rests on the surface. The stacking geometry is pure consumer CSS applied per index via style(i); Snackbar.Queue stays layout-agnostic and only supplies items newest-first, making index 0 the front card. Container height animates between the collapsed and expanded layouts, so surrounding content never jumps.

Hover intent runs through useDelay: entering the surface expands immediately, leaving collapses after a 150ms grace period so the stack doesn’t flicker while the pointer crosses gaps between cards. Auto-dismiss pauses while any item is hovered or focused (WCAG 2.2.1), which you get for free from useNotifications.

The surface owns its notifications instance: createNotificationsContext provides a fresh context under a dedicated namespace, and every Snackbar sub-component receives that namespace so the queue stays isolated from the app-level v0:notifications instance. Use this pattern whenever a toast surface shouldn’t mix with the rest of the app — or, as here, with other examples on the same page.

Reach for this pattern when toasts arrive in bursts and a flat column would push content off screen; for a simple stack with per-item actions, see the undo example above.

Cycles through info → success → warning → error

Snackbar inside a Dialog

Click Open Settings to open the modal dialog, then Save to trigger the snackbar. The snackbar mounts directly inside the dialog’s top-layer subtree via the default teleport="top-layer" — no extra configuration required.

A native <dialog> with showModal() is promoted to the browser top layer, which paints it above all content and makes everything outside its subtree inert. A snackbar teleported to body would render beneath the dialog and be unclickable. Snackbar.Portal avoids this by resolving its target to useStack().topElement — the topmost open modal’s <dialog> element — so the snackbar shares the dialog’s top-layer context and stays interactive.

When the dialog closes, the portal reparents back to body automatically; timers and queue state are preserved because Vue’s Teleport moves the same live DOM nodes rather than re-mounting. To always target body, pass teleport="body"; for inline rendering inside a scoped container, see Inline rendering.

Settings

Adjust your preferences, then save.

Recipes

Teleport target

Snackbar.Portal defaults to teleport="top-layer" so snackbars work automatically when a modal dialog is open. Pass an explicit value to override:

vue
<template>
  <!-- Default: mounts inside the topmost open modal, falls back to body -->
  <Snackbar.Portal><!-- ... --></Snackbar.Portal>

  <!-- Always teleport to body, even inside a modal -->
  <Snackbar.Portal teleport="body"><!-- ... --></Snackbar.Portal>

  <!-- Render inline — no teleport (useful in scoped containers, Storybook) -->
  <Snackbar.Portal :teleport="false"><!-- ... --></Snackbar.Portal>
</template>

ARIA role

Set role directly on Snackbar.Root to control how screen readers announce the notification:

vue
<template>
  <!-- Polite — waits for user to be idle -->
  <Snackbar.Root role="status">
    <Snackbar.Content>Changes saved</Snackbar.Content>
    <Snackbar.Close />
  </Snackbar.Root>

  <!-- Assertive — interrupts immediately -->
  <Snackbar.Root role="alert">
    <Snackbar.Content>Build failed — check logs</Snackbar.Content>
    <Snackbar.Close />
  </Snackbar.Root>
</template>

Inline rendering

Pass :teleport="false" to render the portal inline instead of teleporting to <body>. Useful in docs, Storybook, or scoped container layouts:

vue
<template>
  <div class="relative h-48">
    <Snackbar.Portal :teleport="false" class="absolute bottom-4 right-4">
      <Snackbar.Root>
        <Snackbar.Content>Changes saved</Snackbar.Content>
        <Snackbar.Close />
      </Snackbar.Root>
    </Snackbar.Portal>
  </div>
</template>

Accessibility

ConcernImplementation
Live regionSnackbar.Portal auto-renders Snackbar.Announcer — a visually-hidden polite + assertive pair, mounted empty — and each Snackbar.Root mirrors its text into the matching region on mount, so the first message is reliably announced. Pass :announcer="false" to place <Snackbar.Announcer> yourself. Snackbar.Root still defaults to role="status" (role="alert" when urgent) as best-effort without a Portal.
role="status"Implicit aria-live="polite" — screen reader waits for idle. Use for confirmations and info.
role="alert"Implicit aria-live="assertive" — screen reader interrupts. Use for errors and warnings.
Close buttonSnackbar.Close renders an inline default aria-label of "Dismiss", localizable via the Snackbar.close key.
TimingAuto-dismiss pauses on hover and focus (WCAG 2.2.1). Tabbing into a snackbar pauses the queue; focus leaving the container resumes it.
FocusNo focus trap — snackbars are non-modal.

FAQ

Discord
Need help? Join our community for support and discussions ↗
Was this page helpful?

© 2016-1970 Vuetify, LLC
Services
Ctrl+/