Sur cette page

Accessibilité

#Lien direct vers cette section

Pris en charge automatiquement

#Lien direct vers cette section
  • Élément <dialog> natif avec role="dialog", aria-labelledby, aria-describedby et aria-modal.
  • Quand without-header est actif, aria-label (basé sur label) remplace aria-labelledby — le nom accessible reste garanti même sans header visible.
  • Le focus est déplacé à l’ouverture sur l’élément portant autofocus, ou à défaut sur le premier élément focalisable, ou sur le bouton de fermeture si aucun n’est présent, ou sur le <dialog> lui-même si le header est absent — conforme WCAG 2.1.2 (ouvre dans un nouvel onglet)No Keyboard Trap : le focus clavier peut toujours quitter un composant via les touches standard (Escape, Tab).
  • Le focus est restauré sur l’élément déclencheur à la fermeture.
  • Le scroll du <body> est bloqué à l’ouverture et restauré à la fermeture, y compris avec plusieurs dialogs empilés.
  • La touche Escape passe par ar-dialog-hide : la fermeture peut donc être interceptée avec event.preventDefault() — comportement prévisible conforme WCAG 3.2.2 (ouvre dans un nouvel onglet)On Input : modifier un composant UI ne doit pas provoquer de changement de contexte inattendu sans en avertir l'utilisateur au préalable.
  • Quand une fermeture est bloquée, le composant secoue visuellement le dialog et annonce automatiquement prevented-message via la zone d’annonce globale de la librairie.
  • Les animations sont désactivées si prefers-reduced-motion: reduce est actif.

À votre charge

#Lien direct vers cette section
  • Fournir un label descriptif. Un fallback Dialogue existe, mais il doit rester un filet de sécurité, pas le libellé final du composant. Un avertissement est émis dans la console si ni label ni slot="label" ne sont fournis.
  • without-header retire le bouton de fermeture. label devient requis (le slot label HTML est sans effet dans ce mode), et un moyen de fermeture doit rester accessible — close-on-backdrop, ou une action data-ar-dismiss/data-ar-accept dans votre contenu. Un avertissement est émis en développement si aucun n’est détecté (Échap reste toujours disponible).
  • Toujours proposer une issue claire. Le backdrop est statique par défaut : prévoir un bouton de fermeture visible ou une action data-ar-dismiss.
  • Si vous bloquez la fermeture, renseigner prevented-message. Le message doit expliquer quoi faire pour continuer ou confirmer l’action.
  • Piloter le focus initial si nécessaire. Posez autofocus sur l’élément qui doit recevoir le focus à l’ouverture — utile par exemple pour un champ de saisie dans un drawer.

Utilisation

#Lien direct vers cette section

Déclaration via data-ar-dialog-open

#Lien direct vers cette section

Plutôt que de piloter open en JavaScript, un élément cliquable peut ouvrir un dialog par son id via l’attribut data-ar-dialog-open — un écouteur global au niveau du document intercepte le clic :

<button data-ar-dialog-open="confirm-dialog">Supprimer</button>

<ar-dialog id="confirm-dialog" label="Confirmer la suppression">
    Cette action est irréversible.
    <div slot="footer">
        <button data-ar-dismiss>Annuler</button>
        <button data-ar-accept>Confirmer</button>
    </div>
</ar-dialog>

Personnaliser le header

#Lien direct vers cette section

Le conteneur du slot header-actions expose son propre ::part(header-actions), indépendant du layout titre/fermeture — utile pour définir un espacement entre plusieurs actions sans affecter le reste du header :

ar-dialog::part(header-actions) {
    gap: 0.5rem;
}

Pour masquer visuellement le titre sans casser le nom accessible du dialog, masquez ::part(title) avec la technique sr-only standard — pas display: none ni visibility: hidden, qui peuvent faire perdre le nom accessible calculé via aria-labelledby dans certains navigateurs :

ar-dialog::part(title) {
    position: absolute;
    width: 1px;
    height: 1px;
    overflow: hidden;
    clip: rect(0, 0, 0, 0);
    white-space: nowrap;
}

Cette technique sort le titre du flux (position: absolute), ce qui rompt le margin-inline-end: auto utilisé par le composant pour aligner header-actions et le bouton de fermeture en fin de header. Complétez avec justify-content sur ::part(header) pour conserver cet alignement :

ar-dialog::part(header) {
    justify-content: flex-end;
}

Le slot n’est pas limité à des boutons isolés — un seul enfant slotté peut lui-même porter son propre layout interne (actions à gauche, pagination à droite, titre sr-only…). Voir la variante « Header avancé » pour une démonstration complète.

Pour retirer entièrement le header, voir la variante « Sans header ».

Cycle d’événements

#Lien direct vers cette section

Tous les événements portent detail: { id } (l’id du dialog). data-ar-dismiss et data-ar-accept sont deux conventions distinctes de ar-dialog-hide : elles permettent de distinguer une annulation (“Annuler”) d’une confirmation (“Confirmer”) sur le même geste de fermeture. La liste complète des événements, avec leur annulabilité, est dans la Référence API.

document.getElementById('confirm-dialog').addEventListener('ar-dialog-accepted', (e) => {
    if (e.defaultPrevented) return;
    console.log('Confirmé, dialog :', e.detail.id);
});

Fermeture différée

#Lien direct vers cette section

Pour enregistrer avant de fermer, annulez ar-dialog-accepted et posez pending dans le même gestionnaire. Le dialog reste ouvert, annonce l’attente au lieu d’un blocage et ignore les nouvelles tentatives de fermeture. Une fois la réponse reçue, levez pending puis fermez, ou laissez le dialog ouvert en cas d’échec :

dialog.addEventListener('ar-dialog-accepted', async (e) => {
    e.preventDefault();
    dialog.pending = true; // avant le premier await
    try {
        await save();
        dialog.open = false;
    } finally {
        dialog.pending = false;
    }
});

Le dialog lit pending dès le retour du gestionnaire : posez-le directement sur l’élément, avant tout await. Un pending que votre code applicatif ne reflète sur l’élément qu’après coup (liaison d’attribut mise à jour au prochain rendu, par exemple) arrive trop tard : le dialog a déjà traité l’annulation comme un blocage, avec sa secousse et son annonce. Une liaison peut ensuite refléter l’état affiché, mais elle ne remplace pas cette écriture.

Exemples

#Lien direct vers cette section

Les exemples de cette page sont affichés avec le thème neutre du starter-kit.

Modal

#Lien direct vers cette section

Dialog centré avec backdrop. Cliquer sur le bouton pour l'ouvrir.

Votre session expirera dans 5 minutes. Enregistrez votre travail pour ne pas perdre vos modifications.

Voir le code
<button class="ar-btn ar-btn-primary" data-ar-dialog-open="demo-modal">Ouvrir la modale</button>
<ar-dialog id="demo-modal" label="Informations importantes">
    <p>Votre session expirera dans 5 minutes. Enregistrez votre travail pour ne pas perdre vos modifications.</p>
</ar-dialog>

Drawer droit

#Lien direct vers cette section

Panneau latéral glissant depuis la droite.

Contenu du panneau latéral.

Voir le code
<button class="ar-btn ar-btn-primary" data-ar-dialog-open="demo-drawer">Ouvrir le drawer</button>
<ar-dialog id="demo-drawer" label="Filtres de recherche" mode="drawer">
    <p>Contenu du panneau latéral.</p>
</ar-dialog>

Drawer gauche

#Lien direct vers cette section

Panneau latéral glissant depuis la gauche.

Contenu du panneau latéral gauche.

Voir le code
<button class="ar-btn ar-btn-primary" data-ar-dialog-open="demo-drawer-left">Ouvrir le drawer gauche</button>
<ar-dialog id="demo-drawer-left" label="Menu de navigation" mode="drawer" placement="left">
    <p>Contenu du panneau latéral gauche.</p>
</ar-dialog>

Fermeture au clic backdrop

#Lien direct vers cette section

Par défaut, le backdrop est statique. Avec close-on-backdrop, un clic sur le fond ferme le dialog.

Cliquez en dehors du dialog pour le fermer.

Voir le code
<button class="ar-btn ar-btn-primary" data-ar-dialog-open="demo-backdrop">Ouvrir (close-on-backdrop)</button>
<ar-dialog id="demo-backdrop" label="Informations" close-on-backdrop>
    <p>Cliquez en dehors du dialog pour le fermer.</p>
</ar-dialog>

Actions dans le header

#Lien direct vers cette section

Le slot header-actions permet d'ajouter des actions additionnelles avant le bouton de fermeture (ex. bouton plein écran).

Contenu du dialog, avec une action additionnelle dans le header.

Voir le code
<button class="ar-btn ar-btn-primary" data-ar-dialog-open="demo-header-actions">Ouvrir</button>
<ar-dialog id="demo-header-actions" label="Rapport mensuel">
    <button class="ar-btn ar-btn-secondary" slot="header-actions" aria-label="Passer en plein écran" style="font-size: 1.5rem">⤢</button>
    <p style="margin: 0">Contenu du dialog, avec une action additionnelle dans le header.</p>
</ar-dialog>

Header avancé

#Lien direct vers cette section

Un seul enfant slotté dans header-actions peut porter son propre layout — ici des actions à gauche et une pagination compacte à droite, titre du drawer masqué visuellement (sr-only) au profit d'un titre secondaire visible dans le contenu.

Titre secondaire du volet

Contenu du volet

Voir le code
<button class="ar-btn ar-btn-primary" data-ar-dialog-open="demo-header-advanced">Ouvrir le drawer</button>
<ar-dialog id="demo-header-advanced" class="demo-header-advanced" label="Titre accessible du volet" mode="drawer">
    <div slot="header-actions" class="demo-header-advanced-actions">
        <div class="actions">
            <button class="ar-btn ar-btn-primary">Action 1</button>
            <button class="ar-btn ar-btn-secondary">Action 2</button>
        </div>
        <ar-pagination current="3" total="10"></ar-pagination>
    </div>
    <h2>Titre secondaire du volet</h2>
    <p>Contenu du volet</p>
</ar-dialog>
<style>
    /* Masquage accessible du titre */
    .demo-header-advanced::part(title) {
        position: absolute;
        width: 1px;
        height: 1px;
        overflow: hidden;
        clip: rect(0, 0, 0, 0);
        white-space: nowrap;
    }

    /* Style minimal pour la layout de bloc d'actions */
    .demo-header-advanced-actions {
      display: flex;
      justify-content: space-between;
      align-items: center;
      width: 100%;
      gap: 0.5rem;

      .actions {
        display: flex;
        align-items: center;
        flex: 1 1 100%;
        gap: 0.5rem;
      }
    }
</style>

Sans header

#Lien direct vers cette section

without-header retire titre, actions et bouton de fermeture — label reste requis pour le nom accessible (aria-label). Prévoir un moyen de fermeture (ici close-on-backdrop).

Aperçu
Voir le code
<button class="ar-btn ar-btn-primary" data-ar-dialog-open="demo-without-header">Ouvrir</button>
<ar-dialog id="demo-without-header" label="Aperçu image" without-header close-on-backdrop>
    <img src="https://placehold.co/480x270" alt="Aperçu" style="display:block;width:100%;" />
</ar-dialog>

Focus initial

#Lien direct vers cette section

Posez `autofocus` sur l'élément qui doit recevoir le focus à l'ouverture — ici un champ de recherche dans un drawer.

Voir le code
<button class="ar-btn ar-btn-primary" data-ar-dialog-open="demo-autofocus">Ouvrir le drawer</button>
<ar-dialog id="demo-autofocus" label="Rechercher" mode="drawer">
    <input autofocus type="search" placeholder="Rechercher…" style="width:100%;padding:.5rem .75rem;border:1px solid var(--ar-color-border,#ccc);border-radius:.375rem;font-size:1rem;" />
</ar-dialog>

Dialogs empilés

#Lien direct vers cette section

Ouverture d'un second dialog depuis le premier — scroll lock et focus sont coordonnés. Le scroll de la page reste verrouillé tant qu'un dialog est ouvert, et n'est relâché qu'à la fermeture du dernier. Escape ne ferme que le dialog au sommet.

Ce dialog peut en ouvrir un second par-dessus.

Dialog empilé. Escape ne ferme que ce dialog, pas le précédent.

Voir le code
<button class="ar-btn ar-btn-primary" data-ar-dialog-open="demo-stacked-1">Ouvrir le dialog</button>
<ar-dialog id="demo-stacked-1" label="Dialog principal">
    <p>Ce dialog peut en ouvrir un second par-dessus.</p>
    <button class="ar-btn ar-btn-secondary" data-ar-dialog-open="demo-stacked-2">Ouvrir un second dialog</button>
</ar-dialog>
<ar-dialog id="demo-stacked-2" label="Dialog secondaire">
    <p>Dialog empilé. Escape ne ferme que ce dialog, pas le précédent.</p>
</ar-dialog>

Fermeture bloquée

#Lien direct vers cette section

ar-dialog-hide est annulable : le composant secoue le dialog et annonce automatiquement le blocage aux lecteurs d'écran. Seul le bouton Confirmer ferme.

Ce dialog ne peut être fermé que via le bouton Confirmer. Escape et le bouton de fermeture sont interceptés.

Voir le code
<button class="ar-btn ar-btn-primary" data-ar-dialog-open="demo-persistent">Ouvrir le dialog persistant</button>
<ar-dialog id="demo-persistent" label="Action requise" prevented-message="Fermeture bloquée — utilisez le bouton Confirmer.">
    <p>Ce dialog ne peut être fermé que via le bouton <strong>Confirmer</strong>. Escape et le bouton de fermeture sont interceptés.</p>
    <button class="ar-btn ar-btn-primary" slot="footer" data-ar-accept>Confirmer</button>
</ar-dialog>
<script>
    (function () {
        var dialog = document.getElementById('demo-persistent');
        if (!dialog) return;
        var confirming = false;
        dialog.addEventListener('ar-dialog-accepted', function () { confirming = true; });
        dialog.addEventListener('ar-dialog-hide', function (e) { if (!confirming) e.preventDefault(); confirming = false; });
        dialog.addEventListener('ar-dialog-dismissed', function (e) { e.preventDefault(); });
    })();
</script>

Démo interactive

#Lien direct vers cette section

Manipulez les attributs pour voir le code et la preview se mettre à jour.

Votre session expirera dans 5 minutes. Enregistrez votre travail pour ne pas perdre vos modifications.

<button class="ar-btn ar-btn-primary" data-ar-dialog-open="pg-demo-modal">Ouvrir la modale</button>
<ar-dialog id="pg-demo-modal" label="Informations importantes">
    <p>Votre session expirera dans 5 minutes. Enregistrez votre travail pour ne pas perdre vos modifications.</p>
</ar-dialog>

Référence API

#Lien direct vers cette section

Import

#Lien direct vers cette section

Si vous utilisez l'autoloader, les composants détectés dans la pages sont chargés automatiquement, donc pas besoin de les importer individuellement.
Pour un import manuel, voici comment vous y prendre.

CDNnpm

Importez ce composant depuis le CDN.

<script type="module" src="https://unpkg.com/@ariane-ui/core/dist/components/dialog/index.js"></script>

Après avoir installé le paquet via npm, vous pouvez importer le composant ainsi :

import '@ariane-ui/core/dist/components/dialog/index.js';

Configuration

#Lien direct vers cette section
Attributs et propriétés 10Slots 5Événements 10

Attributs et propriétés

1 sur 10
openreflète

Visibilité du composant.

Type booleanDéfaut false

2 sur 10
closeOnBackdropreflèteclose-on-backdrop

Si présent, un clic sur le backdrop ferme le dialog. Par défaut, le backdrop est statique et ne déclenche pas la fermeture.

Type booleanDéfaut false

3 sur 10
labelreflète

Titre affiché dans le header. Pour du HTML, utiliser `slot="label"`.

Type stringDéfaut ''

4 sur 10
withoutHeaderreflètewithout-header

Si présent, retire entièrement le header (titre, actions, bouton de fermeture) du DOM. La propriété `label` devient alors le seul nom accessible du dialog (`aria-label`) — elle est requise dans ce mode, le slot `label` (HTML) est sans effet.

Type booleanDéfaut false

5 sur 10
modereflète

Mode d'affichage : `modal` (centré avec backdrop) ou `drawer` (panneau latéral).

Type 'modal' | 'drawer'Défaut 'modal'

6 sur 10
placementreflète

Côté d'affichage du drawer. Sans effet en mode `modal`.

Type 'left' | 'right'Défaut 'right'

7 sur 10
sizereflète

Taille du dialog. Les paliers `sm`/`lg`/`xl` sont définis par le thème — sans thème chargé, seule la taille par défaut du composant s'applique. Utilisez `--ar-dialog-width` pour une valeur personnalisée : elle prend le pas sur le palier tant que la règle qui la pose l'emporte dans la cascade (spécificité, ordre, couches `@layer`) sur celle qui définit le palier.

Type 'sm' | 'md' | 'lg' | 'xl'Défaut 'md'

8 sur 10
pendingreflète

Attente d'une réponse, pilotée par l'application : posé dans le gestionnaire d'un `ar-dialog-accepted` (ou `-dismissed`, `-hide`) annulé, il reporte la fermeture au lieu de la bloquer. Le composant n'agit alors ni par secousse ni par annonce de blocage, ignore en silence les nouvelles tentatives de fermeture (clic, Échap, backdrop) et pose `aria-busy="true"` sur le dialogue, l'état `:state(pending)` et une annonce polie de l'attente. L'application le lève (`pending = false`) puis ferme (`open = false`) ou laisse le dialog ouvert. Le composant ne le pose ni ne le retire jamais. Non bloquant pour le contenu : seules les fermetures sont ignorées.

Type booleanDéfaut false

9 sur 10
preventedMessagereflèteprevented-message

Message annoncé aux lecteurs d'écran quand une fermeture est bloquée (événements `ar-dialog-hide-prevented`, `ar-dialog-dismissed-prevented`, `ar-dialog-accepted-prevented`). Traduit automatiquement selon `lang` si non personnalisé.

Type string | undefinedDéfaut undefined

10 sur 10
closeLabelreflèteclose-label

Label accessible du bouton de fermeture. Traduit automatiquement selon `lang` si non personnalisé.

Type string | undefinedDéfaut undefined

Slots

1 sur 5label

Titre du dialog. Remplace la propriété `label` si du HTML est nécessaire. Sans effet si `without-header` est actif.

2 sur 5header-actions

Actions additionnelles dans le header, positionnées avant le bouton de fermeture (ex. bouton plein écran, menu). Retiré du DOM si `without-header` est actif.

3 sur 5(default)

Contenu principal du dialog.

4 sur 5footer

Actions du dialog (boutons). Absent du DOM si non fourni.

5 sur 5close-icon

Icône du bouton de fermeture. Remplace le SVG "×" par défaut. Retiré du DOM si `without-header` est actif.

Événements

1 sur 10
ar-dialog-showannulabledetail : { id: string | undefined }

Émis avant l'ouverture.

2 sur 10
ar-dialog-show-preventeddetail : { id: string | undefined }

Émis si ar-dialog-show est annulé.

3 sur 10
ar-dialog-showndetail : { id: string | undefined }

Émis après l'ouverture (après updateComplete).

4 sur 10
ar-dialog-hideannulabledetail : { id: string | undefined }

Émis avant la fermeture.

5 sur 10
ar-dialog-hide-preventeddetail : { id: string | undefined }

Émis si ar-dialog-hide est annulé, ou si `open` repasse à `true` pendant l'animation de fermeture (la fermeture est alors abandonnée). Sauf report par `pending`, le composant secoue le dialog et annonce `prevented-message` aux lecteurs d'écran.

6 sur 10
ar-dialog-hiddendetail : { id: string | undefined }

Émis après la fermeture (après animation).

7 sur 10
ar-dialog-dismissedannulabledetail : { id: string | undefined }

Émis lors d'un clic sur data-ar-dismiss.

8 sur 10
ar-dialog-dismissed-preventeddetail : { id: string | undefined }

Émis si ar-dialog-dismissed est annulé.

9 sur 10
ar-dialog-acceptedannulabledetail : { id: string | undefined }

Émis lors d'un clic sur data-ar-accept.

10 sur 10
ar-dialog-accepted-preventeddetail : { id: string | undefined }

Émis si ar-dialog-accepted est annulé.

Personnalisation

#Lien direct vers cette section
CSS Parts 8CSS Custom States 2CSS Custom Properties 10

CSS Parts

Utilisez ::part(name) pour styler ces éléments depuis l'extérieur.
Certaines parts indiquent un rôle transverse, partagé avec d'autres composants — voir Personnalisation avancée.

1 sur 8dialog

L'élément <dialog> racine.

2 sur 8header

L'en-tête contenant le titre et le bouton de fermeture. Absent du DOM si `without-header` est actif.

3 sur 8header-actions

Le conteneur des actions additionnelles du header (slot `header-actions`). Absent du DOM si le slot est vide ou si `without-header` est actif.

4 sur 8title

Le titre du dialog.

5 sur 8close-button

Le bouton de fermeture dans l'en-tête. Absent du DOM si `without-header` est actif.

6 sur 8action-button

Porté par `close-button` : bouton qui déclenche une action ponctuelle.

7 sur 8body

La zone de contenu principale.

8 sur 8footer

La zone d'actions (absente du DOM si slot non utilisé).

CSS Custom States

Utilisez le sélecteur :state(name) sur le tag pour styler ce composant en fonction de son état.
Composable avec ::part() pour cibler un élément interne (ar-dialog:state(name)::part(x)).
Sous Chrome et Edge 125, l'état est exposé avec le préfixe -- (:--name) : voir Compatibilité.

1 sur 2:state(open)

Le dialog est ouvert.

2 sur 2:state(pending)

L'application a posé l'attribut `pending` : une réponse est attendue avant de fermer.

CSS Custom Properties

1 sur 10--ar-dialog-width

Largeur du dialog. Prend le pas sur la largeur d'une taille prédéfinie (`size`) tant que la règle qui la pose l'emporte dans la cascade (spécificité, ordre, couches `@layer`) sur celle qui définit cette taille.

2 sur 10--ar-dialog-spacing

Padding interne (block et inline) de la zone de contenu.

3 sur 10--ar-dialog-spacing-block

Padding haut/bas. Prend le pas sur `--ar-dialog-spacing` si défini.

4 sur 10--ar-dialog-spacing-inline

Padding gauche/droite. Prend le pas sur `--ar-dialog-spacing` si défini.

5 sur 10--ar-dialog-backdrop

Couleur de fond du voile derrière le dialog (mode modal).

6 sur 10--ar-dialog-close-size

Taille (width/height) du bouton de fermeture.

7 sur 10--ar-dialog-close-transition-duration

Durée de la transition (background-color) du bouton de fermeture au survol.

8 sur 10--ar-dialog-bg

Fond du dialog (cascade vers --ar-color-bg). Repli `Canvas` si aucun thème n'est chargé — sans thème et sans bordure (le dialog natif perd son style UA par défaut), le contenu flotte sinon sans surface visible.

9 sur 10--ar-dialog-color

Couleur du texte du dialog (cascade vers --ar-color-text). Repli `CanvasText` si aucun thème n'est chargé.

10 sur 10--ar-dialog-shake-outline-color

Couleur de l'anneau de mise en évidence (`outline`) affiché à la place du shake en `prefers-reduced-motion: reduce` (cascade vers --ar-color-danger-text).

Traduction

#Lien direct vers cette section

La langue de ce composant suit l'attribut lang de la page (<html lang>).
Vous pouvez appliquer une langue différente à une instance donnée en posant l'attribut lang directement dessus.
Voir la page Traductions pour le détail du mécanisme et la liste des traductions disponibles.

lang étant un attribut HTML natif, il n'apparaît pas dans le tableau « Attributs & Propriétés ».