Symptôme. La tabulation clavier saute directement du logo à la première section suivant le carrousel d’accueil, sans jamais s’arrêter sur les flèches de navigation ni sur les puces de pagination pourtant visibles à l’écran, sur un carrousel construit avec Slider Revolution. Un test rapide à la souris confirme que ces éléments fonctionnent, seule la voie clavier est coupée.
Ce n’est pas un cas isolé : c’est le comportement par défaut du plugin dans la plupart de ses versions, et il concerne autant les flèches que les puces et le bouton de mise en pause automatique quand celui-ci est activé.
Diagnostic : des div stylées, pas des boutons
En inspectant le DOM généré, les flèches de navigation ne sont pas des éléments <button> ni des <a>, mais des <div> avec des classes comme tp-leftarrow et tp-rightarrow, un gestionnaire de clic attaché en JavaScript, et aucun attribut tabindex, role ou libellé accessible. Un <div> nu n’entre jamais dans l’ordre de tabulation par défaut du navigateur, quel que soit son style visuel.
C’est exactement l’antipattern « role=button sur une div » mais version incomplète : ici, il manque même le role et le tabindex, pas seulement le comportement clavier attendu par la spécification ARIA APG pour un widget de type bouton.

Correctif : un script complémentaire, sans toucher au plugin
Réécrire le plugin lui-même n’est ni réaliste ni souhaitable : les mises à jour écraseraient le correctif. La bonne approche consiste à ajouter, depuis le thème, un script qui enrichit les éléments générés une fois le carrousel initialisé, sans modifier les fichiers du plugin.
document.addEventListener('DOMContentLoaded', function () {
var carrousel = document.querySelector('.rev_slider_wrapper');
if (!carrousel) return;
var boutons = carrousel.querySelectorAll(
'.tp-leftarrow, .tp-rightarrow, .tp-bullet'
);
boutons.forEach(function (bouton) {
bouton.setAttribute('tabindex', '0');
bouton.setAttribute('role', 'button');
if (!bouton.hasAttribute('aria-label')) {
var libelle = bouton.classList.contains('tp-leftarrow')
? 'Diapositive précédente'
: bouton.classList.contains('tp-rightarrow')
? 'Diapositive suivante'
: 'Aller à la diapositive';
bouton.setAttribute('aria-label', libelle);
}
bouton.addEventListener('keydown', function (e) {
if (e.key === 'Enter' || e.key === ' ') {
e.preventDefault();
bouton.click();
}
});
});
});
Ce script fonctionne parce qu’il s’appuie sur le comportement de clic déjà géré par Slider Revolution : on ne réécrit pas la logique de changement de diapositive, on se contente de brancher le clavier sur le même déclencheur que celui utilisé à la souris.
Points de vigilance sur ce correctif
- Vérifier que les classes CSS ciblées (
tp-leftarrow,tp-rightarrow,tp-bullet) n’ont pas changé entre deux versions majeures du plugin - Tester après chaque mise à jour de Slider Revolution : une refonte de son moteur de rendu peut renommer ces classes sans préavis
- Ajouter également
aria-live="polite"sur le conteneur de la diapositive active si le contenu texte change visuellement à chaque transition, pour qu’un lecteur d’écran soit informé du changement - Ne pas oublier la pause automatique : si un bouton play/pause existe, il doit suivre le même traitement
Pourquoi ne pas simplement retirer les flèches ?
Sur certains projets, la tentation est de masquer purement et simplement les flèches pour éviter le problème. Ce n’est pas une bonne réponse : un utilisateur voyant qui navigue au clavier doit pouvoir contrôler le carrousel exactement comme un utilisateur à la souris, pas perdre une fonctionnalité visible à l’écran. Retirer les flèches pénalise tout le monde pour contourner un défaut d’implémentation qui se corrige en quelques lignes.
Prévention pour les futurs projets
Avant de choisir une extension de carrousel propriétaire, un test rapide à la tabulation sur une démo suffit à écarter les solutions les plus fermées. Sur nos projets récents, on préfère de plus en plus un carrousel construit en JavaScript natif avec des <button> réels dès le départ, précisément pour éviter ce type de rattrapage après coup. Quand le choix de l’outil est déjà imposé par le client, le script correctif ci-dessus reste la solution la plus pragmatique : peu invasive, indépendante des mises à jour du cœur du plugin, et facilement transposable à d’autres extensions du même genre.