Back

Comment implémenter des notifications Toast dans Vue

Comment implémenter des notifications Toast dans Vue

Vous devez fournir un retour d’information aux utilisateurs—un formulaire enregistré, un appel API échoué, un téléchargement réussi. Les notifications toast résolvent cela élégamment : des messages brefs qui apparaissent, délivrent l’information et disparaissent sans perturber le flux de travail.

Ce guide couvre deux approches pour les notifications toast dans Vue 3 : la construction d’un système personnalisé basé sur des composables et l’intégration de bibliothèques établies comme Vue Toastification ou Notivue. Les deux utilisent les patterns modernes de la Composition API avec la syntaxe <script setup>.

Points clés à retenir

  • Un système de toast personnalisé dans Vue 3 nécessite seulement trois éléments : un état réactif partagé, une fonction composable et un composant conteneur basé sur Teleport.
  • Les bibliothèques tierces comme Vue Toastification et Notivue gèrent la file d’attente, les animations, l’accessibilité et les thèmes prêts à l’emploi.
  • Dans Nuxt 3, les notifications toast nécessitent une exécution côté client uniquement—utilisez des wrappers <ClientOnly> ou les suffixes de plugin .client.ts.
  • Les toasts accessibles utilisent des régions aria-live, des boutons de fermeture avec des labels clairs et respectent les préférences prefers-reduced-motion.

Construire un système de Toast personnalisé avec les Composables Vue

Un système de notification minimal avec un composable Vue nécessite trois éléments : un état réactif, une fonction composable et un composant rendu utilisant Teleport.

Le Composable Toast

Créez un store réactif partagé accessible par n’importe quel composant :

// 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
  }
}

La ref toasts est déclarée en dehors de la fonction composable afin que chaque appel à useToast() partage le même tableau réactif. Le wrapper readonly empêche les consommateurs de muter l’état directement—seuls add et remove peuvent modifier la liste.

Le composant conteneur Toast

Affichez les toasts en utilisant Teleport pour les positionner en dehors de votre arbre de composants :

<!-- 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="Fermer la notification">×</button>
      </div>
    </div>
  </Teleport>
</template>

Placez <ToastContainer /> dans votre App.vue, puis appelez useToast() depuis n’importe quel composant pour déclencher des notifications.

Note sur les rôles ARIA : Le conteneur utilise aria-live="polite" afin que les lecteurs d’écran annoncent les nouveaux toasts sans interrompre l’utilisateur. Les toasts individuels utilisent role="status" plutôt que role="alert", ce qui s’associe correctement avec la région live polie. Réservez role="alert" (qui implique aria-live="assertive") pour les messages d’erreur urgents qui exigent une attention immédiate.

Utiliser des bibliothèques tierces

Pour les applications en production, les bibliothèques maintenues gèrent les cas limites que vous auriez autrement à construire vous-même : gestion de la file d’attente, animations, accessibilité et thématisation.

Configuration de Vue Toastification

Installez et enregistrez le 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')

Utilisez le composable dans les composants :

<script setup>
import { useToast } from 'vue-toastification'

const toast = useToast()

const handleSave = async () => {
  try {
    await saveData()
    toast.success('Modifications enregistrées')
  } catch {
    toast.error('Échec de l\'enregistrement')
  }
}
</script>

Alternative Notivue

Notivue offre une API composable similaire avec des options de personnalisation supplémentaires et des fonctionnalités d’accessibilité intégrées.

Notifications Toast dans Nuxt 3

Les notifications toast dans Nuxt 3 doivent être déclenchées dans des contextes côté client (par exemple, dans des gestionnaires d’événements ou onMounted) car elles manipulent le DOM et ne doivent pas s’exécuter pendant le rendu côté serveur :

<!-- app.vue -->
<template>
  <NuxtPage />
  <ClientOnly>
    <ToastContainer />
  </ClientOnly>
</template>

Si vous utilisez Nuxt UI, il fournit son propre composable useToast—aucune bibliothèque supplémentaire n’est nécessaire. Pour d’autres configurations, créez un 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)
})

Le suffixe .client.ts garantit que le plugin ne s’exécute que dans le navigateur.

Considérations d’accessibilité

Les toasts doivent être accessibles aux utilisateurs de lecteurs d’écran :

  • Utilisez aria-live="polite" sur le conteneur de toast afin que les nouveaux messages soient annoncés sans interruption
  • Fournissez des boutons de fermeture avec des attributs aria-label descriptifs
  • Respectez prefers-reduced-motion en désactivant les animations lorsque demandé
  • Évitez de fermer automatiquement les messages d’erreur—les utilisateurs ont besoin de temps pour les lire et agir en conséquence
@media (prefers-reduced-motion: reduce) {
  .toast {
    animation: none
  }
}

Conclusion

Construisez un système de toast personnalisé lorsque vous avez besoin d’une taille de bundle minimale ou d’un comportement très spécifique. Utilisez Vue Toastification ou Notivue lorsque vous voulez une accessibilité éprouvée, des animations et des options de configuration sans surcharge de maintenance.

Les deux approches fonctionnent dans Vue 3 et Nuxt 3. Le pattern composable garde votre code testable et vos composants découplés de la logique de notification. Commencez avec le composable personnalisé pour comprendre les mécanismes, puis évaluez si une bibliothèque sert mieux les besoins à long terme de votre projet.

FAQ

Oui. Parce que la ref toasts est déclarée en dehors de la fonction useToast au niveau du module, chaque composant qui appelle useToast partage le même état réactif. Cela signifie que n'importe quel composant peut déclencher ou fermer des toasts sans passer de props ou émettre d'événements à travers les composants parents.

Teleport déplace les nœuds DOM du toast vers l'élément body, en dehors de votre hiérarchie de composants. Cela empêche le CSS parent comme overflow hidden ou les contextes d'empilement z-index de rogner ou cacher vos toasts. Cela maintient également le positionnement des toasts cohérent quel que soit l'endroit où le composant conteneur est monté.

Dans le composable personnalisé, passez zéro ou un nombre négatif comme argument de durée pour ignorer l'appel setTimeout. Avec Vue Toastification, définissez timeout à false pour des toasts spécifiques. Les messages d'erreur doivent persister jusqu'à ce que l'utilisateur les ferme manuellement afin qu'ils aient suffisamment de temps pour les lire et réagir.

Oui. Les notifications toast manipulent le DOM, qui n'est pas disponible pendant le rendu côté serveur. Enveloppez votre conteneur de toast dans un composant ClientOnly ou enregistrez votre bibliothèque de toast comme un plugin Nuxt côté client uniquement en utilisant le suffixe de fichier .client.ts. Cela garantit que la logique des toasts ne s'exécute que dans le navigateur.

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