---
title: Snackbar - Toast and Snackbar Notifications
meta:
- name: description
  content: Headless compound component for rendering toast and snackbar notifications. Snackbar.Queue connects to useNotifications for queue-driven toast stacks.
- name: keywords
  content: snackbar, toast, notification, alert, status, headless, compound component, queue
features:
  category: Component
  label: 'C: Snackbar'
  github: /components/Snackbar/
  renderless: false
  level: 2
related:
  - /composables/plugins/use-notifications
  - /composables/registration/create-queue
---

# Snackbar

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

<DocsPageFeatures :frontmatter />

## Usage

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

::: gn-example
/components/snackbar/basic
:::

## Anatomy

```vue Anatomy no-filename
<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

::: gn-example
/components/snackbar/useToasts.ts 1
/components/snackbar/ToastHost.vue 2
/components/snackbar/toast-host.vue 3

### 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](/composables/plugins/use-notifications); 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](/composables/registration/create-queue) primitive underneath.

| File | Role |
|------|------|
| `useToasts.ts` | Owns the notifications instance and the deletable file list; exposes notify, remove, and the undo restore closure |
| `ToastHost.vue` | Renders the Snackbar.Queue surface — a stacked column of severity-styled toasts, each with a Close and a conditional Undo button |
| `toast-host.vue` | Demo entry — action buttons and a file list wired to the composable, plus the mounted ToastHost |
:::

::: gn-example
/components/snackbar/queue

### 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](/composables/system/use-delay): 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](/composables/plugins/use-notifications).

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.
:::

::: gn-example
/components/snackbar/in-dialog

### 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](#inline-rendering).
:::

## 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 collapse no-filename
<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 collapse no-filename
<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 collapse no-filename
<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

| Concern | Implementation |
|---------|---------------|
| Live region | `Snackbar.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 button | `Snackbar.Close` renders an inline default `aria-label` of `"Dismiss"`, localizable via the `Snackbar.close` key. |
| Timing | Auto-dismiss pauses on hover and focus (WCAG 2.2.1). Tabbing into a snackbar pauses the queue; focus leaving the container resumes it. |
| Focus | No focus trap — snackbars are non-modal. |

## FAQ

::: faq

??? When should I use `Snackbar.Queue` vs a bare `Snackbar.Root`?

Use `Snackbar.Queue` for notifications flowing through [useNotifications](/composables/plugins/use-notifications) — you get auto-dismiss, pause-on-hover, and stacking. For a transient one-off message whose lifecycle you control yourself, render a `Snackbar.Root` without a queue.

??? What's the difference between `ticket.dismiss()` and `Snackbar.Close`?

Inside a queue, `dismiss()` removes the toast from the display queue only — the item survives in the registry (e.g. an inbox). `Snackbar.Close` permanently unregisters it from both the queue and the registry.

??? How do I make a snackbar interrupt screen readers for errors?

Set `role="alert"` on `Snackbar.Root` (implicit `aria-live="assertive"`). The default `role="status"` is polite and waits for the reader to be idle.

??? Does the auto-dismiss timer pause on hover?

Yes. A queued stack pauses on hover and focus (WCAG 2.2.1) and resumes once focus leaves the container — no wiring needed.

??? How do I render snackbars inline instead of teleporting?

Pass `:teleport="false"` on `Snackbar.Portal`, optionally inside a `relative` container, to render the stack in place. (By default `Snackbar.Portal` teleports to `top-layer`, falling back to `<body>` when no modal dialog is open.)

??? How do I add an undo action to a toast?

Attach a closure to the notification's `data` payload when you send it. `Snackbar.Queue` exposes each ticket through its slot, so the host reads `data.undo` and renders an Undo button beside `Snackbar.Close`.

:::

<DocsApi />
