SPA, Modales & Notifications
Chapitre 4 : SPA, Modales & Notifications — Maîtriser le chaos 🌪️
Vous avez fait un formulaire accessible ? Bravo. 👏
Maintenant, l'utilisateur clique sur "Sauvegarder".
Une modale s'ouvre ? Une notification apparaît ? La page change sans rechargement ?
Pour un aveugle ou un utilisateur clavier, si vous ne gérez pas ça, c'est comme être téléporté dans une pièce noire sans prévenir.
Slides
https://gamma.app/docs/SPA-Modales-Notifications--fmit19ze7owq5xp
1. Inertia & Le "Silence" des SPA 🤫
Dans une app classique (Blade, PHP pur), quand on clique sur un lien, la page devient blanche, recharge, et le navigateur annonce le nouveau titre.
Dans une SPA (Inertia/Vue), le changement est visuel et instantané. Le navigateur, lui, reste sur la même "page" technique.
Le risque : L'utilisateur clique sur un lien... et rien ne se passe (pour son lecteur d'écran). Il attend toujours.
La Solution : Le composant <Head> 🧠
Inertia nous donne un super outil. Utilisez-le sur chaque page.
Il met à jour la balise <title> du document. C'est le signal numéro 1 pour dire "Vous avez changé d'endroit".
Extrait de code
<script setup>
import { Head } from '@inertiajs/vue3';
</script>
<template>
<Head title="Créer une maison | Mon Agence" />
<div class="container">
<h1>Créer une maison</h1>
</div>
</template>
💡 Règle : Chaque page vue via Inertia DOIT avoir un
<Head>. C'est votre GPS audio.
2. Les Modales (Dialogues) : Le Piège à Focus 🪤
Les modales, c'est dangereux.
Si vous codez une modale avec juste une div absolute z-50, vous allez créer un enfer :
-
L'utilisateur ouvre la modale.
-
Il appuie sur
Tab. -
Le focus sort de la modale et va sur les liens en arrière-plan (qui sont grisés visuellement !). 😱
Le concept du "Focus Trap" (Hôtel California)
Une bonne modale doit capturer le clavier.
-
✅ Tant qu'elle est ouverte, la touche
Tabtourne en boucle dedans. -
✅ La touche
Echap(Esc) doit la fermer. -
✅ Le clic à l'extérieur (Backdrop) doit la fermer.
-
✅ À la fermeture, le focus doit revenir sur le bouton qui a ouvert la modale (sinon l'utilisateur est perdu).
La Solution : Shadcn (Radix UI) à la rescousse 🛡️
N'écrivez jamais votre propre modale (sauf si vous avez 2 semaines devant vous).
Utilisez le composant Dialog de Shadcn. Il gère tout ça nativement.
Extrait de code
<script setup>
import {
Dialog,
DialogContent,
DialogHeader,
DialogTitle,
DialogTrigger,
} from '@/components/ui/dialog';
import { Button } from '@/components/ui/button';
</script>
<template>
<Dialog>
<DialogTrigger as-child>
<Button variant="outline">Supprimer le compte</Button>
</DialogTrigger>
<DialogContent class="sm:max-w-[425px]">
<DialogHeader>
<DialogTitle>Êtes-vous absolument sûr ?</DialogTitle>
</DialogHeader>
<div class="py-4">
Cette action est irréversible.
</div>
<div class="flex justify-end">
<Button variant="destructive">Confirmer la suppression</Button>
</div>
</DialogContent>
</Dialog>
</template>
À vérifier : Testez toujours que la touche
Echapferme bien votre modale. C'est le réflexe universel.

3. Notifications (Toasts) : "Hey ! Écoute-moi !" 📢
Vous avez supprimé une maison. Une petite notif verte apparaît en bas à droite : "Succès !".
Visuellement, c'est top.
Pour un aveugle qui est en train de lire le menu en haut de page... cette notif n'existe pas.
Les "Live Regions" (Zones vivantes) 📡
HTML a un attribut magique : aria-live.
Il dit au lecteur d'écran : "Surveille cette zone. Si le texte change, lis-le immédiatement."
Il y a deux niveaux de politesse :
-
aria-live="polite"(Poli) : "Attends que l'utilisateur ait fini sa phrase, puis dis-lui." (Utilisé pour les succès, infos). -
aria-live="assertive"(Grossier) : "TAIS-TOI ET ÉCOUTE ÇA !" (Utilisé pour les erreurs critiques, compte à rebours imminent).
Avec Shadcn useToast
Shadcn utilise Radix Toast qui gère ça pour nous.
Par défaut, c'est souvent en mode "polite".
Si vous devez afficher une erreur critique via Inertia (les Flash Messages de Laravel), assurez-vous qu'ils sont injectés dans le composant Toaster correctement.
Extrait de code
<script setup>
import { usePage } from '@inertiajs/vue3';
import { useToast } from '@/components/ui/toast/use-toast';
import { watch } from 'vue';
const page = usePage();
const { toast } = useToast();
// Observer les messages flash de Laravel
watch(() => page.props.flash, (flash) => {
if (flash.success) {
toast({
title: "Succès",
description: flash.success,
// Radix gère aria-live="polite" par défaut pour le variant 'default'
});
}
if (flash.error) {
toast({
title: "Erreur",
description: flash.error,
variant: "destructive",
// Le variant destructive devrait passer en assertif ou rester poli selon l'urgence
});
}
}, { deep: true });
</script>

4. Ce qu'il faut retenir pour les SPAs 📝
-
Changement de page :
-
Mettre à jour le
<Head title="..." />. -
Reset du focus (vu au chapitre 2).
-
-
Modales :
-
Utilisez Shadcn/Radix. Ne bricolez pas.
-
Vérifiez le Focus Trap.
-
-
Notifications :
-
Connectez les Flash Messages Laravel au système de Toasts.
-
Vérifiez qu'ils sont lus (les logs ARIA dans Chrome DevTools aident à voir ça).
-
Synthèse

