Cómo Implementar Notificaciones Toast en Vue
Necesitas mostrar retroalimentación a los usuarios: un formulario guardado, una llamada API fallida, una carga exitosa. Las notificaciones toast resuelven esto de manera elegante: mensajes breves que aparecen, entregan información y desaparecen sin interrumpir el flujo de trabajo.
Esta guía cubre dos enfoques para notificaciones toast en Vue 3: construir un sistema personalizado basado en composables e integrar bibliotecas establecidas como Vue Toastification o Notivue. Ambos usan patrones modernos de la Composition API con sintaxis <script setup>.
Puntos Clave
- Un sistema toast personalizado en Vue 3 necesita solo tres piezas: estado reactivo compartido, una función composable y un componente contenedor basado en Teleport.
- Las bibliotecas de terceros como Vue Toastification y Notivue manejan la gestión de colas, animaciones, accesibilidad y tematización de forma predeterminada.
- En Nuxt 3, las notificaciones toast requieren ejecución solo en el cliente—usa envoltorios
<ClientOnly>o sufijos de plugin.client.ts. - Los toasts accesibles usan regiones
aria-live, botones de cierre con etiquetas claras y respetan las preferenciasprefers-reduced-motion.
Construyendo un Sistema Toast Personalizado con Composables de Vue
Un sistema de notificaciones composable mínimo en Vue requiere tres piezas: estado reactivo, una función composable y un componente renderizado usando Teleport.
El Composable Toast
Crea un almacén reactivo compartido al que cualquier componente pueda acceder:
// composables/useToast.ts
import { ref, readonly } from 'vue'
interface Toast {
id: number
message: string
type: 'success' | 'error' | 'info' | 'warning'
}
const toasts = ref<Toast[]>([])
let id = 0
export function useToast() {
const add = (message: string, type: Toast['type'] = 'info', duration = 3000) => {
const toast = { id: ++id, message, type }
toasts.value.push(toast)
if (duration > 0) {
setTimeout(() => remove(toast.id), duration)
}
}
const remove = (toastId: number) => {
toasts.value = toasts.value.filter(t => t.id !== toastId)
}
return {
toasts: readonly(toasts),
success: (msg: string) => add(msg, 'success'),
error: (msg: string) => add(msg, 'error'),
info: (msg: string) => add(msg, 'info'),
warning: (msg: string) => add(msg, 'warning'),
remove
}
}
El ref toasts se declara fuera de la función composable para que cada llamada a useToast() comparta el mismo array reactivo. El envoltorio readonly previene que los consumidores muten el estado directamente—solo add y remove pueden modificar la lista.
El Componente Contenedor de Toast
Renderiza los toasts usando Teleport para posicionarlos fuera de tu árbol de componentes:
<!-- components/ToastContainer.vue -->
<script setup lang="ts">
import { useToast } from '@/composables/useToast'
const { toasts, remove } = useToast()
</script>
<template>
<Teleport to="body">
<div
class="toast-container"
role="region"
aria-live="polite"
aria-label="Notifications"
>
<div
v-for="toast in toasts"
:key="toast.id"
:class="['toast', `toast--${toast.type}`]"
role="status"
>
{{ toast.message }}
<button @click="remove(toast.id)" aria-label="Dismiss notification">×</button>
</div>
</div>
</Teleport>
</template>
Coloca <ToastContainer /> en tu App.vue, luego llama a useToast() desde cualquier componente para activar notificaciones.
Nota sobre roles ARIA: El contenedor usa
aria-live="polite"para que los lectores de pantalla anuncien nuevos toasts sin interrumpir al usuario. Los toasts individuales usanrole="status"en lugar derole="alert", que se empareja correctamente con la región live polite. Reservarole="alert"(que implicaaria-live="assertive") para mensajes de error urgentes que demandan atención inmediata.
Usando Bibliotecas de Terceros
Para aplicaciones en producción, las bibliotecas mantenidas manejan casos extremos que de otro modo tendrías que construir tú mismo: gestión de colas, animaciones, accesibilidad y tematización.
Configuración de Vue Toastification
Instala y registra el plugin:
// main.ts
import { createApp } from 'vue'
import Toast from 'vue-toastification'
import 'vue-toastification/dist/index.css'
import App from './App.vue'
const app = createApp(App)
app.use(Toast, {
position: 'top-right',
timeout: 5000
})
app.mount('#app')
Usa el composable en los componentes:
<script setup>
import { useToast } from 'vue-toastification'
const toast = useToast()
const handleSave = async () => {
try {
await saveData()
toast.success('Changes saved')
} catch {
toast.error('Save failed')
}
}
</script>
Discover how at OpenReplay.com.
Alternativa Notivue
Notivue ofrece una API composable similar con opciones adicionales de personalización y características de accesibilidad integradas.
Notificaciones Toast en Nuxt 3
Las notificaciones toast en Nuxt 3 deben activarse en contextos del lado del cliente (por ejemplo, en manejadores de eventos o onMounted) porque manipulan el DOM y no deben ejecutarse durante el renderizado del lado del servidor:
<!-- app.vue -->
<template>
<NuxtPage />
<ClientOnly>
<ToastContainer />
</ClientOnly>
</template>
Si estás usando Nuxt UI, proporciona su propio composable useToast—no se necesita biblioteca adicional. Para otras configuraciones, crea un plugin de Nuxt:
// plugins/toast.client.ts
import Toast from 'vue-toastification'
import 'vue-toastification/dist/index.css'
export default defineNuxtPlugin((nuxtApp) => {
nuxtApp.vueApp.use(Toast)
})
El sufijo .client.ts asegura que el plugin solo se ejecute en el navegador.
Consideraciones de Accesibilidad
Los toasts deben ser accesibles para usuarios de lectores de pantalla:
- Usa
aria-live="polite"en el contenedor de toasts para que los nuevos mensajes se anuncien sin interrupción - Proporciona botones de cierre con atributos
aria-labeldescriptivos - Respeta
prefers-reduced-motiondeshabilitando animaciones cuando se solicite - Evita el cierre automático de mensajes de error—los usuarios necesitan tiempo para leer y actuar sobre ellos
@media (prefers-reduced-motion: reduce) {
.toast {
animation: none
}
}
Conclusión
Construye un sistema toast personalizado cuando necesites un tamaño de bundle mínimo o comportamiento altamente específico. Usa Vue Toastification o Notivue cuando quieras accesibilidad probada, animaciones y opciones de configuración sin sobrecarga de mantenimiento.
Ambos enfoques funcionan en Vue 3 y Nuxt 3. El patrón composable mantiene tu código testeable y tus componentes desacoplados de la lógica de notificaciones. Comienza con el composable personalizado para entender la mecánica, luego evalúa si una biblioteca sirve mejor las necesidades a largo plazo de tu proyecto.
Preguntas Frecuentes
Sí. Debido a que el ref toasts se declara fuera de la función useToast a nivel de módulo, cada componente que llama a useToast comparte el mismo estado reactivo. Esto significa que cualquier componente puede activar o cerrar toasts sin pasar props o emitir eventos a través de componentes padre.
Teleport mueve los nodos DOM del toast al elemento body, fuera de tu jerarquía de componentes. Esto previene que el CSS padre como overflow hidden o contextos de apilamiento z-index recorten u oculten tus toasts. También mantiene el posicionamiento del toast consistente independientemente de dónde se monte el componente contenedor.
En el composable personalizado, pasa cero o un número negativo como argumento de duración para omitir la llamada setTimeout. Con Vue Toastification, establece timeout en false para toasts específicos. Los mensajes de error deben persistir hasta que el usuario los cierre manualmente para que tengan suficiente tiempo para leer y responder.
Sí. Las notificaciones toast manipulan el DOM, que no está disponible durante el renderizado del lado del servidor. Envuelve tu contenedor de toast en un componente ClientOnly o registra tu biblioteca de toast como un plugin de Nuxt solo para cliente usando el sufijo de archivo .client.ts. Esto asegura que la lógica de toast solo se ejecute en el navegador.
Gain Debugging Superpowers
Unleash the power of session replay to reproduce bugs, track slowdowns and uncover frustrations in your app. Get complete visibility into your frontend with OpenReplay — the most advanced open-source session replay tool for developers. Check our GitHub repo and join the thousands of developers in our community.