Modal
Contrairement aux autres composants TDS, le modal nécessite un minimum de JavaScript : l’élément
<dialog> natif ne s’ouvre pas en pur CSS. En contrepartie, <dialog> gère nativement le
piège à focus (focus trap), la fermeture avec Échap et le ::backdrop — pas de librairie requise.
Do / Don’t
✓ Faire
- Réserver le modal aux actions qui nécessitent une confirmation ou une interruption du flux
- Garder le contenu court — un modal n’est pas une page
✗ Éviter
- Empiler plusieurs modals (modal ouvrant un modal)
- Mettre un formulaire complet multi-étapes dans un modal — préférer une page dédiée
Rendu statique (attribut open) pour la QA visuelle — l’ouverture réelle passe par dialog.showModal().
Tailles
| Taille | Classe | Max-width |
|---|---|---|
sm | tds-modal tds-modal--sm | 24rem |
md (défaut) | tds-modal | 32rem |
lg | tds-modal tds-modal--lg | 48rem |
Importation
@import "@tds-tchad/core/components/modal/modal.css";import { modal } from '@tds-tchad/core/components/modal';import type { ModalSize } from '@tds-tchad/core/components/modal';Exemples
<button type="button" class="tds-button tds-button--primary tds-button--md" onclick="document.getElementById('confirm-modal').showModal()"> Soumettre la demande</button>
<dialog id="confirm-modal" class="tds-modal" aria-labelledby="confirm-modal-title"> <div class="tds-modal__header"> <h2 id="confirm-modal-title" class="tds-modal__title">Confirmer la soumission</h2> <button type="button" class="tds-modal__close" aria-label="Fermer" onclick="this.closest('dialog').close()">✕</button> </div> <div class="tds-modal__body"> <p>Votre demande sera transmise au service concerné. Cette action est définitive.</p> </div> <div class="tds-modal__footer"> <button type="button" class="tds-button tds-button--tertiary tds-button--md" onclick="this.closest('dialog').close()"> Annuler </button> <button type="button" class="tds-button tds-button--primary tds-button--md">Confirmer</button> </div></dialog>import { useRef } from 'react';import '@tds-tchad/core/components/modal/modal.css';import type { ModalSize } from '@tds-tchad/core/components/modal';
interface ModalProps { title: string; size?: ModalSize; children: React.ReactNode;}
export function Modal({ title, size = 'md', children }: ModalProps) { const ref = useRef<HTMLDialogElement>(null);
return ( <dialog ref={ref} className={`tds-modal ${size !== 'md' ? `tds-modal--${size}` : ''}`} aria-labelledby="modal-title" > <div className="tds-modal__header"> <h2 id="modal-title" className="tds-modal__title">{title}</h2> <button type="button" className="tds-modal__close" aria-label="Fermer" onClick={() => ref.current?.close()}> ✕ </button> </div> <div className="tds-modal__body">{children}</div> </dialog> );}
// Ouverture : dialogRef.current?.showModal()