Skip to content

ToastContainer

The Vue component that renders toasts. Place it once in App.vue (or in your Nuxt layout). Uses <Teleport to="body"> internally.

vue
<ToastContainer
  position="bottom-right"
  :max-visible="5"
  :gap="8"
  :offset-x="16"
  :offset-y="16"
  :z-index="9999"
  theme="system"
/>

Props

PropTypeDefaultDescription
positionToastPosition'bottom-right'Default container position (per-toast position option overrides this)
maxVisiblenumber5Maximum number of toasts shown at once; extras wait in a pending queue
gapnumber8Vertical gap between toasts in pixels
offsetXnumber16Horizontal distance from the screen edge in pixels
offsetYnumber16Vertical distance from the screen edge in pixels
zIndexnumber9999CSS z-index of the container
expandbooleanfalseExpand all groups immediately (skip collapsed state)
teleportTostring'body'CSS selector passed to <Teleport>
contextToastContextglobalPass an isolated context from createToastContext()
theme'light' | 'dark' | 'system' | ToastDesignTokensTheme name or inline token overrides
stackModebooleanfalseSonner-style stack: inactive toasts collapse behind the front one; hover expands

Multiple containers

A single <ToastContainer> handles all positions automatically — each toast is rendered at its own position option, falling back to the container's position prop:

ts
toast.success('Saved', { position: 'top-right' })
toast.error('Failed', { position: 'bottom-center' })
// Both appear in their respective corners from one <ToastContainer>

For fully isolated queues (separate notification zones), use createToastContext() with a dedicated container:

vue
<template>
  <!-- Default global queue — bottom right -->
  <ToastContainer position="bottom-right" />

  <!-- Critical alerts — top center, separate queue -->
  <ToastContainer position="top-center" :context="alertCtx" :z-index="10000" />
</template>

<script setup lang="ts">
import { createToastContext, useToast } from 'vue-toast-kit'
const alertCtx = createToastContext()
const alertToast = useToast(alertCtx)
</script>

Slots

Override any part of the toast without losing the queue logic:

vue
<ToastContainer>
  <!-- Replace the entire toast -->
  <template #toast="{ toast, dismiss }">
    <MyCustomToast :data="toast" @close="dismiss(toast.id)" />
  </template>
</ToastContainer>
SlotPropsDescription
#toast{ toast, dismiss }Full replacement of one toast (skips all sub-slots)
#toast-icon{ toast }Replace the icon only; falls back to ToastIcon
#toast-content{ toast }Replace the entire message + actions area
#toast-action{ toast }Replace the action / undo buttons; falls back to ToastActions
#toast-close{ toast, dismiss }Replace the close button
#toast-undo{ toast, remaining }Replace the progress bar at the bottom of the toast

Grouping

Toasts with the same groupKey are collapsed into a single toast with a +N counter. Clicking the counter toggles the expanded state.

ts
// All three calls produce one visible toast with "+2"
toast.info('New message from Alice', { groupKey: 'messages' })
toast.info('New message from Bob', { groupKey: 'messages' })
toast.info('New message from Carol', { groupKey: 'messages' })

The leader toast (first in the group) stays visible; subsequent toasts are hidden but tracked. When the leader is dismissed, the next toast becomes the leader automatically.

Grouping options

OptionBehaviour
groupKey: 'my-key'Enable grouping for this toast
No groupKeyToast is always shown individually

Stack mode (Sonner-style)

Enable stackMode on <ToastContainer> to collapse multiple toasts into a visual stack. The front toast is fully visible; behind it you see up to 2 ghost cards, slightly scaled and offset. Hovering the container expands them back to the normal stacked list.

vue
<ToastContainer :stack-mode="true" position="bottom-right" />

Hover to expand, mouse-leave to collapse back.