Back

Como Implementar Notificações Toast no Vue

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.ts em plugins.
  • Toasts acessíveis usam regiões aria-live, botões de dispensar com rótulos claros e respeitam preferências de prefers-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 usam role="status" em vez de role="alert", que combina corretamente com a região live polite. Reserve role="alert" (que implica aria-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>

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-label descritivos
  • Respeite prefers-reduced-motion desabilitando 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.

OpenReplay