# Architecture d’un assistant conversationnel accessible intégré à un thème

> Un client voulait un assistant conversationnel maison sur son thème WordPress, utilisable au clavier et au lecteur d'écran dès la première version. Voici l'architecture retenue.

- Auteur : Clément Hadrot
- Publié le : 2024-10-14
- Mis à jour le : 2024-10-14
- Catégorie : Accessibilité
- URL : https://wpmoderne.dev.wordpress-developpement.fr/accessibilite/architecture-assistant-conversationnel-accessible-theme/

## L’essentiel

- Une région aria-live dédiée annonce chaque réponse sans déplacer le focus
- Le fil de conversation reste un historique lisible, pas une suite de bulles décoratives
- Le piège de focus classique des fenêtres modales s'applique aussi à un panneau de chat

Un client éditeur de formations en ligne souhaitait intégrer, directement dans son thème WordPress, un assistant conversationnel maison capable de répondre aux questions fréquentes sur son catalogue, plutôt que d'utiliser une solution de chatbot tierce clé en main. La contrainte posée dès le cadrage était explicite : l'assistant devait être utilisable dès sa première version par une personne naviguant exclusivement au clavier ou avec un lecteur d'écran, sans traitement correctif après coup. Ce billet ne compare pas cette approche maison aux chatbots tiers non accessibles, sujet distinct qui sera traité séparément en 2025, mais détaille l'architecture technique retenue pour ce projet précis.

## Vue d'ensemble de l'architecture

L'assistant se compose d'un panneau ouvrable depuis un bouton fixe dans le thème, d'un fil de conversation, d'un champ de saisie, et d'une communication asynchrone avec un service de génération de réponses côté serveur. Le point de départ du projet n'a pas été l'apparence visuelle du panneau, mais sa structure sémantique et la circulation du focus, posées avant même le premier essai de mise en page.

```
assistant-accessible/
├── panneau/
│   ├── bouton-ouverture.php     # déclenche le panneau, aria-expanded
│   ├── panneau-conversation.php # role="dialog", aria-modal, piège de focus
│   ├── fil-messages.php         # historique, liste de messages sémantique
│   └── champ-saisie.php         # formulaire, label explicite
├── regions-live/
│   ├── annonce-reponse.php      # aria-live="polite", nouvelle réponse
│   └── annonce-statut.php       # aria-live="polite", "L'assistant réfléchit..."
└── js/
    └── assistant.js             # gestion du focus, piège, envoi asynchrone
```

## Le piège de focus, comme pour toute fenêtre modale

Le panneau de conversation, une fois ouvert, se comporte comme une fenêtre modale au sens de l'accessibilité : le focus doit y rester piégé tant qu'il est ouvert, revenir sur le bouton d'ouverture à la fermeture, et l'ensemble du reste de la page doit être neutralisé pour les technologies d'assistance via `aria-hidden="true"` le temps que le panneau est actif. Ce mécanisme, déjà bien documenté pour les fenêtres modales classiques, s'applique à l'identique à un panneau de chat, un point souvent négligé parce qu'un chat « ne ressemble pas » visuellement à une modale traditionnelle.

> L'essentiel à retenir : Une région aria-live dédiée annonce chaque réponse sans déplacer le focus ; Le fil de conversation reste un historique lisible, pas une suite de bulles décoratives ; Le piège de focus classique des fenêtres modales s'applique aussi à un panneau de chat

## Trois régions ARIA distinctes, chacune avec un rôle précis

Le choix le plus structurant de l'architecture a été de ne pas tout annoncer dans une seule région `aria-live` générique, ce qui aurait produit des annonces confuses ou redondantes. Trois régions distinctes ont été mises en place :

- **Annonce de statut** (`aria-live="polite"`) : signale « L'assistant réfléchit... » pendant l'attente de la réponse du serveur, puis se vide une fois la réponse reçue.
- **Annonce de réponse** (`aria-live="polite"`, `aria-atomic="true"`) : contient le texte de la nouvelle réponse de l'assistant, lu automatiquement dès son apparition, sans déplacer le focus du champ de saisie.
- **Fil de conversation** (une liste HTML classique, `<ol>` de messages) : sert d'historique consultable à tout moment en naviguant au clavier, indépendamment des annonces automatiques déjà entendues.

Cette séparation permet à une personne qui suit la conversation en temps réel d'entendre chaque nouvelle réponse sans que son focus ne quitte le champ de saisie, tout en gardant la possibilité de revenir consulter l'historique complet à son rythme, sans redéclencher d'annonce automatique.

## Le champ de saisie et l'envoi asynchrone

Le champ de saisie reste un `<textarea>` avec un `<label>` explicite (« Posez votre question »), et le bouton d'envoi est un véritable `<button type="submit">`, pas un simple élément cliquable en JavaScript. L'envoi déclenche l'appel asynchrone au service de génération, mais le focus reste sur le champ de saisie pendant toute l'attente, pour permettre d'enchaîner une nouvelle question sans manipulation supplémentaire une fois la réponse arrivée.

```
<form aria-describedby="assistant-statut">
  <label for="assistant-question">Posez votre question</label>
  <textarea id="assistant-question" name="question"></textarea>
  <button type="submit">Envoyer</button>
</form>
<div id="assistant-statut" aria-live="polite"></div>
```

## En résumé

L'architecture d'un assistant conversationnel accessible repose sur des principes déjà connus par ailleurs — piège de focus d'une modale, régions `aria-live` bien délimitées, formulaire sémantique classique — mais leur combinaison demande une attention particulière pour ne pas multiplier les annonces ou perdre le focus pendant les échanges. Poser cette structure dès la conception, plutôt que de l'ajouter après une première version pensée uniquement pour la souris, a évité au client plusieurs allers-retours coûteux de correction.
