data-wp-bind--aria-selected : cette directive de l’Interactivity API, introduite avec WordPress 6.5 en avril 2024, permet en principe de synchroniser un attribut ARIA avec un état réactif sans écrire une ligne de JavaScript personnalisé. Sur un composant d’onglets récemment mis à jour, elle a pourtant cessé de fonctionner correctement après l’ajout d’une mise à jour partielle du contenu.
Le symptôme observé sur ce site : cliquer sur le deuxième onglet affiche bien le bon panneau de contenu, la classe visuelle active se déplace correctement, mais un lecteur d’écran continue d’annoncer le premier onglet comme sélectionné. Le décalage entre ce qui s’affiche et ce qui s’annonce rend le composant trompeur pour qui ne s’appuie pas sur la vue.
Symptôme : deux sources de vérité qui divergent
L’inspection du DOM après un clic révèle exactement ce point de divergence :
<!-- Attendu après clic sur l'onglet 2 -->
<button role="tab" aria-selected="false">Onglet 1</button>
<button role="tab" aria-selected="true">Onglet 2</button>
<!-- Observé réellement -->
<button role="tab" aria-selected="true">Onglet 1</button>
<button role="tab" aria-selected="false">Onglet 2</button>
Le panneau associé, lui, affiche pourtant bien le contenu du second onglet. Il y a donc deux mécanismes distincts en jeu dans ce composant : l’un pour l’affichage du panneau, correctement mis à jour, l’autre pour l’état ARIA des boutons, resté figé.

Diagnostic : un contexte non lu au bon endroit
Le fichier view.js du bloc définissait bien un magasin réactif avec un état d’onglet actif, mais le marquage HTML des boutons n’utilisait pas la directive data-wp-bind pour l’attribut aria-selected : celui-ci avait été codé en dur dans le gabarit au moment du rendu initial côté serveur, sans jamais être repris par une directive côté client.
// store.js d'origine, incomplet
import { store, getContext } from '@wordpress/interactivity';
store('mon-theme/onglets', {
actions: {
selectionnerOnglet() {
const context = getContext();
context.ongletActif = context.index;
},
},
// aucun état dérivé exposé pour aria-selected
});
Le panneau de contenu, lui, utilisait bien data-wp-bind--hidden relié à un état dérivé comparant l’index courant à l’onglet actif, ce qui explique pourquoi il se mettait à jour correctement pendant que le bouton restait figé sur son attribut codé en dur au rendu initial.
Correctif : relier explicitement l’attribut au contexte réactif
La correction consiste à ajouter un état dérivé dans le magasin, puis à lier aria-selected à cet état via data-wp-bind, exactement comme cela avait été fait pour la visibilité du panneau :
// store.js corrigé
import { store, getContext } from '@wordpress/interactivity';
store('mon-theme/onglets', {
state: {
get estSelectionne() {
const context = getContext();
return context.ongletActif === context.index;
},
},
actions: {
selectionnerOnglet() {
const context = getContext();
context.ongletActif = context.index;
},
},
});
<button
role="tab"
data-wp-on--click="actions.selectionnerOnglet"
data-wp-bind--aria-selected="state.estSelectionne"
>
Onglet 2
</button>
Deux ajouts suffisent : l’état dérivé estSelectionne côté magasin, et la directive data-wp-bind--aria-selected côté gabarit. Une fois ce lien posé, le clic sur un onglet met à jour simultanément le panneau visible et l’attribut ARIA du bouton, sans code supplémentaire.
Prévention : ne jamais coder en dur un attribut d’état
Ce type de régression apparaît presque toujours de la même manière : un attribut d’état ARIA écrit une fois au rendu initial côté serveur, jugé suffisant au moment du développement parce que le premier onglet est effectivement sélectionné par défaut, puis jamais relié à la logique réactive qui gère les interactions suivantes. La règle de prévention est simple : chaque attribut qui reflète un état changeant doit passer par une directive data-wp-bind, jamais par une valeur figée dans le gabarit.
Conseil maison : testez toujours le deuxième clic, pas seulement le premier. Un état par défaut correct masque souvent une synchronisation manquante.
En résumé
L’Interactivity API ne synchronise que ce qu’on lui demande explicitement de synchroniser : un panneau visuel et un attribut ARIA sont deux cibles distinctes, même s’ils dépendent conceptuellement du même état. Vérifier que chaque attribut porteur de sens pour les technologies d’assistance est bien relié à une directive réactive évite ce genre d’écart, difficile à repérer visuellement mais immédiatement gênant à l’usage d’un lecteur d’écran.