Baptiste Drillien
Baptiste Drillien

Développeur Next.js - Freelance

Disponible - Me contacter

Dialog, Drawer et Modal en Next.js : choisir le bon niveau d'interruption

Des drawers utilisés comme des pages, des dialogs qui scrollent ou qui prennent toute la page, des confirmations inutiles, et des problèmes d’accessibilité.

Le problème, c’est pas le composant. C’est le mauvais niveau d’interruption.

À quel point on bloque l’utilisateur ?

Choisir le bon niveau évite soit d’interrompre inutilement, soit de noyer une action critique dans le flow utilisateur.

Avant de choisir entre Dialog, Drawer ou page dédiée, il faut maîtriser les bases a11y et le cadre décisionnel. C’est ce que cet article propose : a11y + UX + architecture front + design system.

Les fondamentaux a11y : dialog, modal, alert

Dialog (role="dialog")

En ARIA, un dialog est une zone qui s’affiche par-dessus la page et regroupe du contenu ou des call to actions (boutons, champs, formulaire).

Il peut être modal ou non modal. C’est le même role="dialog", la différence vient de aria-modal et du comportement (focus trap, inert).

Les obligations : un label (aria-labelledby ou aria-label) et une gestion du focus cohérente. Sans ça, les lecteurs d’écran et la navigation clavier deviennent imprévisibles.

En pratique, les librairies de composants comme Base UI, Radix UI, Shadcn ou encore Vaul gèrent le rôle, le label et le focus automatiquement.

Modal dialog

Avec aria-modal="true" :

Modal = comportement, pas apparence : focus piégé dans le dialog et arrière-plan inerte.

Une simple div en position: fixed et z-index élevé ressemble à un dialog, mais la tabulation et les lecteurs d’écran peuvent encore atteindre le contenu derrière : en terme d’accessibilité, ce n’est pas optimal.

Exemples typiques :

Dialog modal Base UI : interruption explicite, arrière-plan assombri

Non-modal dialog

Sans blocage : l’utilisateur peut interagir avec l’arrière-plan.

Malheureusement souvent sous-utilisé au profit du tout-modal alors qu’il est beaucoup plus UX friendly.

Ce sont les Popovers, Tooltips, Toasts, Dropdowns, etc. qui ne bloquent pas l’utilisateur.

Base UI propose même un composant Drawer non-modal.

Très utile pour :

Toast non-modal Base UI : pas d'interruption

Alert et Alertdialog : deux rôles ARIA distincts du dialog

En plus du role="dialog", ARIA définit deux rôles dédiés aux messages et confirmations : role="alert" et role="alertdialog".

Ce ne sont pas des variantes du dialog, mais des patterns à part pour des cas précis.

Rôle ARIABloquantAction requise
dialog (modal ou non-modal)✅ ou ❌✅ ou ❌
alert (non-modal)
alertdialog (modal)

Base UI, Radix UI, Shadcn proposent même des composants AlertDialog qui gèrent automatiquement le rôle, le label et le focus :

AlertDialog Base UI : confirmation bloquante

Dialog vs Drawer : faux débat

Un Drawer n’est pas un pattern ARIA.

C’est une variation spatiale d’un dialog (ouverture latérale, souvent depuis un bord).

Les mêmes enjeux s’appliquent : modal ou non, focus trap, label.

Dialog centré : interruption explicite

Dialog Base UI : interruption explicite avec le contenu initial

Drawer latéral : continuité contextuelle

Le choix n’est pas esthétique, il est cognitif. Centré = rupture. Latéral = continuité.

Pour les drawers en React, Vaul est une option headless dédiée ; Base UI vient de release son nouveau composant Drawer (en février 2026).

Drawer Base UI : continuité contextuelle avec le contenu initial

Choisir entre Dialog et Drawer, modal ou non-modal

Quatre questions suffisent pour trancher.

Question 1 : L’utilisateur doit-il arrêter ce qu’il fait ?

Question 2 : Le contenu dépend-il visuellement de l’arrière-plan ?

Question 3 : Le contenu mérite-t-il une URL ?

Question 4 : Quelle est la densité ?

Résumé des user flows typiques

Selon la situation

 Faible densitéForte densité
Faible interruptionTooltip / PopoverDrawer non-modal
Forte interruptionDialog court centréDrawer modal ou Page dédiée

Exemples concrets

SituationPattern recommandé
Message systèmealert
Confirmation critiquealertdialog
Formulaire courtdialog
Édition dense contextuelledrawer
Workflow majeurpage dédiée

Les erreurs fréquentes

Modal sans focus trap

Un drawer qui bloque l’arrière-plan mais ne piège pas le focus : la tabulation « sort » du drawer, la navigation clavier et les lecteurs d’écran deviennent incohérents.

Avec les librairies dédiées comme Base UI, Radix, Headless UI, etc. : le focus trap est géré nativement.

Dialog scrollable sur toute la hauteur

Un dialog qui fait 90 % de l’écran et scroll comme une page : charge cognitive élevée et perte du repère « c’est une interruption courte ».

Dans ce cas, mieux vaut passer à un drawer voire même une page dédiée.

Confirmation Dialog superflue

« Êtes-vous sûr de vouloir enregistrer ? » pour une action non destructive : ça agace et habitue à fermer sans lire.

Réserver les dialogs aux vraies confirmations comme une suppression ou un engagement légal.

Workflow complexe

Multi-étapes, formulaires longs dans un dialog : pas d’URL, pas d’historique, pas de deep link.

Navigation clavier et historique navigateur ne reflètent pas l’état. Dans ce cas, préférer une page dédiée.

Multiplication des overlays empilés

Dialog sur Dialog ou Drawer sur Drawer : focus et annonces lecteur d’écran se mélangent.

Il vaut mieux limiter l’empilement (un overlay à la fois) ou prévoir une librairie qui gère correctement le focus et l'accessibilité comme Vaul ou Base UI pour les drawers.

Pour les Dialogs, il vaut mieux éviter l'empilement.

Checklist a11y minimale pour un élément modal

Avec <dialog> et showModal(), le navigateur gère nativement une partie (backdrop, Escape, inert).

Avec une solution custom, tout doit être implémenté ou délégué à une librairie (headless ou déjà stylisée).

Vous pouvez retrouver une multitude de librairies headless dans cet article. Il est également important de bien choisir ses librairies (notamment en se basant sur mon autre article sur le sujet).

Pourquoi les librairies n’utilisent presque jamais <dialog> ?

Sur le papier, <dialog> semble parfait : backdrop natif, showModal(), gestion d’Escape, inert automatique.

En pratique, les librairies l’évitent souvent.

Pourquoi ?

Résultat : les librairies préfèrent recréer le pattern (focus trap, inert, aria-modal) pour garder une maîtrise complète du comportement.

<dialog> n’est pas “mauvais”. Il est simplement moins flexible dans des architectures complexes comme React et Next.js.

Conclusion : le bon niveau d’interruption

Une interface mature maîtrise ses interruptions.

Plus on bloque, plus il faut le justifier. Les éléments modal (Dialog, Drawer) sont des outils puissants, mais coûteux cognitivement.

Il faut les réserver aux cas où l’interruption apporte une réelle valeur.

Résumé des décisions importantes : éviter les dialogs scroll géant et les confirmations superflues.

Pour aller plus loin, The A11Y Collective — Modal vs Dialog et les docs Radix Dialog, Headless UI Dialog, Base UI Dialog et Vaul sont des références solides.