États d'erreur
Problème
Une erreur doit être actionnable : dire ce qui s'est passé, pourquoi, et ce que l'utilisateur peut faire. Ni stack-trace brute, ni message générique vide de sens.
3 niveaux d'erreur
1. error.tsx (route-level)
Next.js rend src/app/**/error.tsx quand un Server Component lève. Doit proposer un reset() et, si applicable, un lien de repli.
2. Bannière inline (form / section)
Au-dessus du formulaire ou de la section concernée, avec AlertCircle + couleur --color-negative.
<div
role="alert"
className="flex items-start gap-3 rounded-lg border border-[var(--color-negative)]/30 bg-[var(--color-negative)]/5 p-4"
>
<AlertCircle size={16} className="text-[var(--color-negative)] mt-0.5" aria-hidden="true" />
<div>
<p className="text-sm font-semibold text-[var(--color-negative)]">
Import impossible
</p>
<p className="text-xs text-muted">
Le fichier dépasse 5 Mo. Segmentez-le par mois.
</p>
</div>
</div>
3. Toast (action transient)
Erreur non-bloquante suite à une action ponctuelle. Disparaît après 5 s, peut être fermé manuellement.
Règles
role="alert"obligatoire sur les bannières d'erreur (annonce immédiate aux lecteurs d'écran)- Copy actionnable : décrit la cause + la résolution
- Jamais de stack-trace côté utilisateur — logger côté serveur, afficher un ID de corrélation si nécessaire
- Icône
AlertCirclesystématiquement pour distinguer de l'info - Ne pas cacher l'erreur après un timeout sur les bannières bloquantes (réservé aux toasts)
Hiérarchie visuelle
| Sévérité | Traitement |
|---|---|
| Bloquant (validation, auth) | Bannière inline rouge, pas de timeout |
| Transient (action CRUD) | Toast 5 s |
| Critique (500, fatal) | Page error.tsx avec bouton « Réessayer » |
À ne pas faire
- « Une erreur est survenue » sans contexte
- Toast pour une erreur bloquante (disparaît avant que l'utilisateur ne lise)
- Masquer l'erreur en fermant silencieusement un dialog