# « Interactive controls must not be nested » : un bouton bloqué dans un lien

> Une carte produit entièrement cliquable cache un bouton « Ajouter au panier » imbriqué dans le lien. Résultat : un avertissement axe et une navigation clavier cassée.

- Auteur : WordPress Développement
- Publié le : 2023-03-22
- Mis à jour le : 2023-03-22
- Catégorie : Accessibilité
- URL : https://www.wpmoderne.fr/accessibilite/bouton-imbrique-lien-interactive-controls-nested/

## L’essentiel

- Le symptôme se voit d'abord dans les DevTools d'accessibilité
- Le HTML n'autorise pas un bouton dans un lien
- Trois structures de remplacement possibles

« Interactive controls must not be nested » : ce message d'axe DevTools ou de Lighthouse apparaît régulièrement sur des cartes produit ou des cartes d'article entièrement cliquables, où un développeur a voulu ajouter un bouton d'action rapide sans repenser la structure du lien englobant.

Le symptôme est simple à observer, la cause un peu moins évidente au premier regard, et la correction demande de sortir du réflexe « je mets un div cliquable avec un bouton dedans ». Ce texte ne traite pas du style visuel de la carte, seulement de sa structure interactive.

## Symptôme : un bouton invisible pour le clavier

Sur une grille de produits, chaque carte est cliquable dans son intégralité pour aller vers la fiche produit, et affiche en plus un bouton « Ajouter au panier » directement sur la vignette. Le markup ressemble typiquement à ceci :

```
<a href="/produit/lampe-nomade" class="carte-produit">
  <img src="lampe.jpg" alt="Lampe nomade">
  <h3>Lampe nomade</h3>
  <button onclick="ajouterPanier(42)">Ajouter au panier</button>
</a>
```

Au clavier, la tabulation ne s'arrête qu'une fois sur la carte entière : le bouton interne n'est jamais atteignable indépendamment, et son `onclick` ne se déclenche donc jamais par la touche Entrée ou Espace. À la souris, le comportement semble correct puisque le clic sur le bouton remonte visuellement au bon endroit, ce qui masque le problème lors de tests rapides.

## Diagnostic : le HTML n'autorise pas cette imbrication

La spécification HTML interdit un élément interactif (bouton, lien, champ de formulaire) à l'intérieur d'un autre élément interactif. Le navigateur, tolérant, affiche quand même quelque chose à l'écran, mais le modèle d'accessibilité qui en résulte est indéfini : chaque navigateur et chaque lecteur d'écran improvise sa propre interprétation, ce qui explique les comportements incohérents observés d'un environnement à l'autre.

### Pourquoi les tests automatisés le détectent si bien

La règle axe-core `nested-interactive` parcourt l'arbre du DOM à la recherche exactement de ce motif : un rôle interactif contenu dans un autre rôle interactif. C'est l'un des tests les plus fiables du jeu de règles axe, avec très peu de faux positifs, ce qui en fait un excellent candidat pour un test bloquant en intégration continue.

> L'essentiel à retenir : Le symptôme se voit d'abord dans les DevTools d'accessibilité ; Le HTML n'autorise pas un bouton dans un lien ; Trois structures de remplacement possibles

## Correctif : trois structures de remplacement

La première option, la plus simple, consiste à sortir le bouton du lien englobant en le plaçant en frère plutôt qu'en enfant, avec un positionnement CSS en superposition si le visuel doit rester identique.

```
<div class="carte-produit">
  <a href="/produit/lampe-nomade" class="carte-produit__lien">
    <img src="lampe.jpg" alt="Lampe nomade">
    <h3>Lampe nomade</h3>
  </a>
  <button onclick="ajouterPanier(42)">Ajouter au panier</button>
</div>
```

La deuxième option supprime le lien englobant : seul le titre du produit devient un lien, et le reste de la carte n'est plus interactif visuellement, ce qui simplifie considérablement la structure au prix d'une zone cliquable plus réduite.

La troisième option, plus avancée, conserve la carte entièrement cliquable via un gestionnaire de clic en JavaScript sur le conteneur, tout en gardant un vrai lien accessible caché derrière le titre pour le clavier, et un bouton d'action indépendant à côté, jamais imbriqué.

- Bouton et lien en frères, positionnés en CSS si besoin visuellement
- Seul le titre devient un lien, la carte perd son clic global
- Un lien accessible masqué visuellement, plus un clic JavaScript sur le conteneur

## Prévention : interdire le motif dès la revue de code

Ajoutez la règle axe `nested-interactive` à votre pipeline de tests, sur les gabarits de listing produit ou d'articles en particulier. Une simple recherche dans le code des composants « carte » avant fusion d'une pull request permet aussi de repérer ce motif à l'œil, une fois qu'on sait ce qu'on cherche.

> Sur nos projets e-commerce, ce motif de bouton imbriqué revient presque à chaque nouvelle grille de produits construite sans revue systématique du composant carte.

## En résumé

Un bouton imbriqué dans un lien fonctionne à la souris et casse silencieusement au clavier : sortez toujours les éléments interactifs les uns des autres, quitte à repenser la zone cliquable de la carte, et laissez un test automatisé surveiller ce motif en continu.
