Modale
La modale est un élément de mise en forme de contenu permettant de concentrer l’attention de l’usager exclusivement sur une tâche ou un élément d’information, sans perdre le contexte de la page en cours.
HTML
Structure du composant
Le composant Modale permet d'afficher du contenu en plein écran.
Sa structure est la suivante :
-
Le bouton d'ouverture de la modale est défini par la classe
fr-btn
et l'attributaria-controls
lié à l'ID de la modale.- Le bouton doit être de type "button".
-
Le bouton dispose d'un attribut
data-fr-opened
, sa valeur [true|false] défini si la modale est ouverte ou fermée.
-
La modale, définie par la classe
fr-modal
, est un élément HTML<dialog>
.-
Elle dispose d'un attribut
id
obligatoire, pour être lié au bouton d'ouverture. -
La modale est liée à son titre via l'attribut
aria-labelledby
, dont la valeur doit correspondre à l'attributid
du titre.
-
Elle dispose d'un attribut
-
Son contenu est structuré :
-
D'un premier conteneur défini par la classe
fr-container
. -
D'une grille définie par les classes
fr-grid-row
etfr-grid-row--center
. -
D'un bloc de colonne définie par les classes
fr-col-12 fr-col-md-8 fr-col-lg-6
pouvant varier en fonction de la taille de la modale désirée. -
Le corps de la modale défini par la classe
fr-modal__body
, contenant :-
L'entête de la modale, obligatoire, défini par la classe
fr-modal__header
, contenant :-
Le bouton de fermeture de la modale, obligatoire,
est un élément HTML
<button>
, défini par les classesfr-btn
etfr-btn--close
, dont le titre est "Fermer". - Le bouton doit être de type "button".
-
Le bouton est lié à la modale via l'attribut
aria-controls
, sa valeur doit correspondre à l'attributid
de la modale.
-
Le bouton de fermeture de la modale, obligatoire,
est un élément HTML
-
D'un bloc de contenu, obligatoire, défini par la classe
fr-modal__content
, contenant :-
Le titre de la modale, obligatoire, dans un niveau
d'entête
<hx>
ou un paragraphe<p>
et défini par la classefr-modal__title
. -
Le contenu de la modale, obligatoire et libre, mais
nécessitant l'utilisation de balises adéquates, il
n'est pas correcte par exemple de placer du texte
directement dans une
<div>
.
-
Le titre de la modale, obligatoire, dans un niveau
d'entête
-
Le pied de page de la modale, optionnel défini par la
classe
fr-modal__footer
, contenant :-
Un groupe de boutons d'action défini par les classes
fr-btns-group fr-btns-group--right fr-btns-group--inline-reverse fr-btns-group--inline-lg fr-btns-group--icon-left
pouvant varier en fonction de l'affichage désiré des boutons, contenant :- Soit un bouton primaire ( Bouton ).
- Soit un groupe de boutons hiérarchisé.
-
Un groupe de boutons d'action défini par les classes
-
L'entête de la modale, obligatoire, défini par la classe
-
D'un premier conteneur défini par la classe
Exemple de structure HTML
<button data-fr-opened="false" aria-controls="modal" type="button" class="fr-btn">Modale simple</button>
<dialog id="modal" class="fr-modal" aria-labelledby="modal-title" aria-modal="true">
<div class="fr-container fr-container--fluid fr-container-md">
<div class="fr-grid-row fr-grid-row--center">
<div class="fr-col-12 fr-col-md-8 fr-col-lg-6">
<div class="fr-modal__body">
<div class="fr-modal__header">
<button aria-controls="modal" title="Fermer" type="button" class="fr-btn--close fr-btn">Fermer</button>
</div>
<div class="fr-modal__content">
<h2 id="modal-title" class="fr-modal__title">
<span class="fr-icon-arrow-right-line fr-icon--lg" aria-hidden="true"></span>
Titre de la modale
</h2>
<p>
<!-- contenu de la modale -->
</p>
</div>
</div>
</div>
</div>
</div>
</dialog>
CSS
Installation du CSS
Pour fonctionner correctement, les styles CSS du core et de la
modale doivent être importés. L'import doit se faire avant le
contenu de la page dans la partie
<head>
, et de
préférence avec le fichier minifié, car plus léger.
<link href="dist/core/core.min.css" rel="stylesheet">
<link href="dist/component/modal/modal.min.css" rel="stylesheet">
NB : Il est aussi possible d'importer le CSS global du DSFR
dsfr.min.css
.
Pour fonctionner sur Internet Explorer 11, un fichier legacy peut aussi être importé :
<link href="dist/core/core.legacy.min.css" rel="stylesheet">
<link href="dist/component/modal/modal.legacy.min.css" rel="stylesheet">
Variantes de taille
La modale peut avoir différentes tailles en fonction du nombre de colonnes de la grille qui la compose (Voir grille ), sur mobile la modale sera toujours sur 12 colonnes :
- 4 colonnes en LG et 6 colonnes en MD pour une modale SM.
- Par défaut : 6 colonnes en LG et 8 colonnes en MD pour une modale MD.
- 8 colonnes en LG et 10 colonnes en MD pour une modale LG.
Exemples de variantes de taille
<div class="fr-col-12 fr-col-md-6 fr-col-lg-4">
<!-- Contenu de la grille de la modale SM -->
</div>
<div class="fr-col-12 fr-col-md-8 fr-col-lg-6">
<!-- Contenu de la grille de la modale MD -->
</div>
<div class="fr-col-12 fr-col-md-10 fr-col-lg-8">
<!-- Contenu de la grille de la modale LG -->
</div>
Variantes avec zone d'action et boutons
La modale avec une zone d’action permet de guider l’utilisateur vers des actions attendues. Par défaut elle reprend les éléments de la modale simple auxquels s’ajoute une zone d’action obligatoire, composée soit d’un bouton primaire, soit d’un groupe de boutons hiérarchisé.
Exemple de modale avec zone d'action et boutons
<button data-fr-opened="false" aria-controls="modal-action" type="button" class="fr-btn">Modale avec zone d'action</button>
<dialog id="modal-action" class="fr-modal" aria-labelledby="modal-action-title">
<div class="fr-container fr-container--fluid fr-container-md">
<div class="fr-grid-row fr-grid-row--center">
<div class="fr-col-12 fr-col-md-8 fr-col-lg-6">
<div class="fr-modal__body">
<div class="fr-modal__header">
<button aria-controls="modal-action" title="Fermer" type="button" class="fr-btn--close fr-btn">Fermer</button>
</div>
<div class="fr-modal__content">
<h2 id="modal-action-title" class="fr-modal__title">
<span class="fr-icon-arrow-right-line fr-icon--lg" aria-hidden="true"></span>
Titre de la modale
</h2>
<p><!-- contenu de la modale --></p>
</div>
<!-- Zone d'action de la modale -->
<div class="fr-modal__footer">
<div class="fr-btns-group fr-btns-group--right fr-btns-group--inline-reverse fr-btns-group--inline-lg fr-btns-group--icon-left">
<button type="button" class="fr-btn fr-icon-checkbox-circle-line fr-btn--icon-left">Libellé bouton</button>
<button type="button" class="fr-btn fr-icon-checkbox-circle-line fr-btn--icon-left fr-btn--secondary">Libellé bouton</button>
</div>
</div>
</div>
</div>
</div>
</div>
</dialog>
Variantes avec zone d'action ancré en haut en mobile
La zone d’action de la modale peut être placée en haut de
la modale sur mobile avec l'utilisation de la classe
fr-modal--top
.
Exemple de modale avec zone d'action ancré en haut en mobile
<dialog id="modal-action-top" class="fr-modal fr-modal--top" aria-labelledby="modal-action-top-title" aria-modal="true">
<!-- Contenu de la modale -->
</dialog>
Variantes modale simple non refermable au clic sur le fond
Par défaut la modale se referme au clic sur le fond de la page, il
est possible de contourner ce comportement avec l'utilisation de
l'attribut
data-fr-concealing-backdrop="false"
.
Exemple de modale simple non refermable au clic sur le fond
<dialog id="modal-backdrop" class="fr-modal" aria-labelledby="modal-backdrop-title" aria-modal="true" data-fr-concealing-backdrop="false">
<!-- Contenu de la modale -->
</dialog>
JavaScript
Installation du JavaScript
Pour fonctionner le composant modale nécessite l'utilisation de JavaScript. Chaque composant utilisant javascript possède un fichier Js spécifique et requiert le fichier Js du core.
Il est donc nécessaire d'importer ces fichiers à la fin de la page
(avant </body>
) :
<script type="module" src="dist/core/core.module.min.js"></script>
<script type="module" src="dist/component/modal/modal.module.min.js"></script>
NB: Il est aussi possible d'importer le Js global du DSFR
dsfr.module.js
Pour fonctionner sur Internet Explorer 11, un fichier legacy, en version nomodule ES5, peut aussi être importé :
<script type="text/javascript" nomodule href="dist/legacy/legacy.nomodule.min.js" ></script>
<script type="text/javascript" nomodule src="dist/core/core.nomodule.min.js"></script>
<script type="text/javascript" nomodule src="dist/component/modal/modal.nomodule.min.js"></script>
Une fois le JavaScript chargé, le composant fonctionne automatiquement.
Instances
Sur la modale, les éléments suivants sont instanciés :
-
La modale, via la classe :
fr-modal
-
Le bouton d'ouverture de la modale, via l'attribut
aria-controls
Une fois chargé, le Js ajoute un attribut
data-fr-js-NOM_INSTANCE="true"
sur chacun des éléments instanciés
API
Il est possible d'interagir avec les instances du composants en JavaScript via une API.
Cette API est disponible depuis la méthode
window.dsfr(instance)
du
core.
Exemple :
const elem = document.getElementById('modal');
dsfr(elem).modal.disclose();
L'ensemble des propriétés et méthodes disponibles sont définies ci-après :
modal
Description | Défini si le fonctionnement de la modale est activé ou non |
---|---|
Type | property |
Retour | Boolean |
Exemple |
dsfr(elem).modal.isEnabled = false
|
Description | Ferme la modale |
---|---|
Type | function |
Arguments | none |
Retour | none |
Exemple |
dsfr(elem).modal.conceal()
|
Description | Ouvre la modale |
---|---|
Type | function |
Arguments | none |
Retour | none |
Exemple |
dsfr(elem).modal.disclose()
|
Description | Retourne vrai si la modale est ouverte |
---|---|
Type | property |
Retour | Boolean |
Exemple |
dsfr(elem).modal.isDisclosed
|
Description | Renvoie le noeud HTML de l'élément. |
---|---|
Type | property |
Retour | DOMElement |
Exemple |
dsfr(elem).modal.node
|
modalButton
Description | Replace le focus sur le bouton |
---|---|
Type | function |
Arguments | none |
Retour | Boolean |
Exemple |
dsfr(elem).modalButton.focus()
|
Description | Retourne l'instance du dsfr parente, ici la modale |
---|---|
Type | property |
Retour | object | null |
Exemple |
dsfr(elem).parent
|
Description | Renvoie le noeud HTML de l'élément. |
---|---|
Type | property |
Retour | DOMElement |
Exemple |
dsfr(elem).modalButton.node
|
Événements
Le Système de Design fournit des événements personnalisés pour les actions uniques de la part de certains composants réactifs listés sur la page de l' API Javascript .
Sur la modale, les événements suivants sont disponibles :
Événement | Action | Élément | Attribut |
---|---|---|---|
dsfr.conceal
|
Fermeture de la modale | Modal |
data-fr-js-modal
|
dsfr.disclose
|
Ouverture de la modale | Modal |
data-fr-js-modal
|
dsfr.click
|
Click sur le bouton d'ouverture | ModalButton |
data-fr-js-modal-button
|
Note de version
Voir les évolutions sur github
v1.14.0 - 25 juin 2025
v1.13.2 - 15 mai 2025
correction warning console header
Lorsque le header est désactivé en desktop, le js de header retire l'aria-label de la modal car inutile. Le message d'avertissement dans la console indique alors que la modal ne contient pas d'attribut aria. Cette vérification ne doit être faite que si la modale est active. #1120
#1154
v1.13.1 - 26 mars 2025
bouton non requis + correctif
- focusManager gère le retour du focus en cas d'absence d'un bouton primaire.
- correction du bug focus bloqué sur les menu du header
#1103
v1.13.0 - 4 décembre 2024
correction modal footer z-index
- Passage du footer de la modale au niveau de z-index "overlap-above", permettant d'être au dessus du tooltip
#1000
input sans type bug dans le focus trap de la modale
- Correction d'une erreur js liée au focus trap lorsqu'un champ de saisie n'a pas d'attribut "type" dans une modale
#992
v1.11.0 - 11 décembre 2023
a11y retire la liste dans la zone d'actions
-
le groupe de bouton peut désormais être une
div
à la place d'unul``li
- retrait de la liste non ordonnée dans le footer de la modale
#720
v1.10.0 - 19 juillet 2023
retour de focus fermeture clavier
- Mise en place du retour du focus à la fermeture en pressant la touche ESC
#716
préviens décalage mobile
- l'ajout d'un padding à l'ouverture permet de se substituer au décalage créé potentiellement par la disparition de la scrollbar en desktop
- En mobile, la modale occupe 100% de la largeur, ce padding créé un espacement incorrect
- ajout d'une media query sur le breakpoint MD pour corriger le problème
#699
interaction globale et focus iOS
- Correctif à la pression de la touche Escape sur la modale : si l'élément actif (focus) est un élément de formulaire ou un média, la modale n'est pas refermée pas pour permettre l'interaction native de l'élément actif
- Correctif iOS de la prise de focus au clic
- Fermeture des tooltips dés au clic sur n'importe quel endroit
- Fermeture des tooltip à la pression sur la touche escape, où que soit le focus
#691
suppression exemple des liens dans la zone d'action
- Ce cas n'est pas recommandé, la zone d'action étant plutôt prévue pour des boutons
#663
décalage scrollbar à l'ouverture/fermeture modale & fix scroll behavior
Lorsque la page est scrollable, un décalage se produit à l'ouverture d'une modal (la page étant figé elle n'est plus scrollable).
Une marge est donc appliquée à l'ouverture de la modale pour simuler la barre de scroll et ainsi éviter le mouvement du contenu en arrière plan.
#519
v1.9.3 - 17 mai 2023
correction ombre modal footer
L'ombre du footer de la modal scrollable est mal placée et trop forte.
- Remplacement de l'ombre par une bordure d'1px en defaut-grey en haut du footer
- remplacement du token de background-color du footer par background-lifted-grey
- ajout d'un texte plus long dans l'exemple modal + footer pour faire apparaître le scroll
#572
v1.9.1 - 11 avril 2023
correctif prise de focus au focus-trap
à l'ouverture de la modale, le focus est automatiquement déplacé sur le premier des éléments interactifs de la modale. Ce comportement pose problème lorsque le focus est déjà sur un des éléments contenus dans la modale.
Ajout d'une condition qui vérifie que le focus n'est pas déjà sur un des éléments interactifs de la modale avant de déplacer le focus.
#566