Toast / Notification
<div role="status">
Short-lived feedback about the result of an action. Appears in a corner of the viewport and auto-dismisses after a few seconds.
Overview
Preview
Variants
Success
Preview
Changes saved
Your project was updated successfully.
html
<div role="status" class="flex items-start gap-3 rounded-xl border border-emerald-800/40 bg-zinc-900 px-4 py-3.5 shadow-xl">
<div class="mt-0.5 flex h-5 w-5 shrink-0 items-center justify-center rounded-full bg-emerald-950">
<!-- checkmark icon -->
</div>
<div>
<p class="text-sm font-semibold text-emerald-300">Changes saved</p>
<p class="mt-0.5 text-xs text-zinc-500">Your project was updated successfully.</p>
</div>
</div>Error
Preview
Failed to save
Check your connection and try again.
html
<div role="alert" class="... border-red-800/40 ...">
<p class="text-sm font-semibold text-red-300">Failed to save</p>
</div>Toast manager (Nuxt composable)
Create a global toast system with a Nuxt composable:
ts
// composables/useToast.ts
import { ref } from 'vue'
export type ToastType = 'success' | 'error' | 'info'
interface Toast {
id: number
type: ToastType
title: string
body?: string
}
const toasts = ref<Toast[]>([])
let nextId = 0
export function useToast() {
function add(type: ToastType, title: string, body?: string, duration = 4000) {
const id = nextId++
toasts.value.push({ id, type, title, body })
setTimeout(() => remove(id), duration)
}
function remove(id: number) {
toasts.value = toasts.value.filter(t => t.id !== id)
}
return { toasts, add, remove }
}vue
<!-- components/ToastContainer.vue -->
<script setup>
import { useToast } from '~/composables/useToast'
const { toasts, remove } = useToast()
</script>
<template>
<Teleport to="body">
<div class="fixed bottom-4 right-4 z-50 flex flex-col gap-2 w-80">
<TransitionGroup
enter-active-class="transition ease-out duration-200"
enter-from-class="opacity-0 translate-y-2"
enter-to-class="opacity-100 translate-y-0"
leave-active-class="transition ease-in duration-150"
leave-from-class="opacity-100"
leave-to-class="opacity-0 translate-x-4"
>
<div v-for="toast in toasts" :key="toast.id" class="...">
<!-- toast markup -->
</div>
</TransitionGroup>
</div>
</Teleport>
</template>Then use anywhere:
ts
const { add } = useToast()
add('success', 'Saved!', 'Your changes were applied.')Accessibility notes
- Success/info toasts:
role="status"(polite announcement) - Error toasts:
role="alert"(immediate announcement) - Include a dismiss button so keyboard and screen reader users can remove the toast manually
- Don't auto-dismiss error toasts — users need time to read and act on failures