Como Implementar Notificações Toast no Vue
Você precisa mostrar feedback aos usuários—um formulário salvo, uma chamada de API que falhou, um upload bem-sucedido. As notificações toast resolvem isso de forma elegante: mensagens breves que aparecem, entregam informação e desaparecem sem interromper o fluxo de trabalho.
Este guia cobre duas abordagens para notificações toast no Vue 3: construir um sistema customizado baseado em composables e integrar bibliotecas estabelecidas como Vue Toastification ou Notivue. Ambas usam padrões modernos da Composition API com sintaxe <script setup>.
Principais Conclusões
- Um sistema de toast customizado no Vue 3 precisa de apenas três peças: estado reativo compartilhado, uma função composable e um componente container baseado em Teleport.
- Bibliotecas de terceiros como Vue Toastification e Notivue lidam com gerenciamento de fila, animações, acessibilidade e temas prontos para uso.
- No Nuxt 3, notificações toast requerem execução apenas no cliente—use wrappers
<ClientOnly>ou sufixos.client.tsem plugins. - Toasts acessíveis usam regiões
aria-live, botões de dispensar com rótulos claros e respeitam preferências deprefers-reduced-motion.
Construindo um Sistema de Toast Customizado com Composables do Vue
Um sistema mínimo de notificação com composables do Vue requer três peças: estado reativo, uma função composable e um componente renderizado usando Teleport.
O Composable de Toast
Crie um store reativo compartilhado que qualquer componente possa acessar:
// 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
}
}
O ref toasts é declarado fora da função composable para que cada chamada a useToast() compartilhe o mesmo array reativo. O wrapper readonly previne que consumidores mutem o estado diretamente—apenas add e remove podem modificar a lista.
O Componente Container de Toast
Renderize toasts usando Teleport para posicioná-los fora da sua árvore 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>
Coloque <ToastContainer /> no seu App.vue, então chame useToast() de qualquer componente para disparar notificações.
Nota sobre roles ARIA: O container usa
aria-live="polite"para que leitores de tela anunciem novos toasts sem interromper o usuário. Toasts individuais usamrole="status"em vez derole="alert", que combina corretamente com a região live polite. Reserverole="alert"(que implicaaria-live="assertive") para mensagens de erro urgentes que demandam atenção imediata.
Usando Bibliotecas de Terceiros
Para aplicações em produção, bibliotecas mantidas lidam com casos extremos que você construiria de outra forma: gerenciamento de fila, animações, acessibilidade e temas.
Configuração do Vue Toastification
Instale e registre o 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')
Use o composable em 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 oferece uma API composable similar com opções adicionais de customização e recursos de acessibilidade integrados.
Notificações Toast no Nuxt 3
Notificações toast no Nuxt 3 devem ser disparadas em contextos client-side (por exemplo, em manipuladores de eventos ou onMounted) porque manipulam o DOM e não devem executar durante a renderização no servidor:
<!-- app.vue -->
<template>
<NuxtPage />
<ClientOnly>
<ToastContainer />
</ClientOnly>
</template>
Se você está usando Nuxt UI, ele fornece seu próprio composable useToast—nenhuma biblioteca adicional necessária. Para outras configurações, crie um plugin Nuxt:
// plugins/toast.client.ts
import Toast from 'vue-toastification'
import 'vue-toastification/dist/index.css'
export default defineNuxtPlugin((nuxtApp) => {
nuxtApp.vueApp.use(Toast)
})
O sufixo .client.ts garante que o plugin execute apenas no navegador.
Considerações de Acessibilidade
Toasts devem ser acessíveis para usuários de leitores de tela:
- Use
aria-live="polite"no container de toast para que novas mensagens sejam anunciadas sem interrupção - Forneça botões de dispensar com atributos
aria-labeldescritivos - Respeite
prefers-reduced-motiondesabilitando animações quando solicitado - Evite dispensar automaticamente mensagens de erro—usuários precisam de tempo para ler e agir sobre elas
@media (prefers-reduced-motion: reduce) {
.toast {
animation: none
}
}
Conclusão
Construa um sistema de toast customizado quando você precisar de tamanho de bundle mínimo ou comportamento altamente específico. Use Vue Toastification ou Notivue quando você quiser acessibilidade comprovada, animações e opções de configuração sem sobrecarga de manutenção.
Ambas as abordagens funcionam no Vue 3 e Nuxt 3. O padrão composable mantém seu código testável e seus componentes desacoplados da lógica de notificação. Comece com o composable customizado para entender a mecânica, então avalie se uma biblioteca atende melhor as necessidades de longo prazo do seu projeto.
Perguntas Frequentes
Sim. Como o ref toasts é declarado fora da função useToast no nível do módulo, cada componente que chama useToast compartilha o mesmo estado reativo. Isso significa que qualquer componente pode disparar ou dispensar toasts sem passar props ou emitir eventos através de componentes pai.
Teleport move os nós DOM do toast para o elemento body, fora da sua hierarquia de componentes. Isso previne que CSS pai como overflow hidden ou contextos de empilhamento z-index cortem ou escondam seus toasts. Também mantém o posicionamento do toast consistente independentemente de onde o componente container está montado.
No composable customizado, passe zero ou um número negativo como argumento duration para pular a chamada setTimeout. Com Vue Toastification, defina timeout como false para toasts específicos. Mensagens de erro devem persistir até que o usuário as dispense manualmente para que tenham tempo suficiente para ler e responder.
Sim. Notificações toast manipulam o DOM, que não está disponível durante a renderização no servidor. Envolva seu container de toast em um componente ClientOnly ou registre sua biblioteca de toast como um plugin Nuxt client-only usando o sufixo de arquivo .client.ts. Isso garante que a lógica de toast execute apenas no 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.