Comment un bloc de paiement se comporte-t-il quand un visiteur navigue uniquement au clavier, sans jamais toucher la souris ? C’est la question posée par une association qui voulait collecter des dons ponctuels via un bloc dynamique dédié, sans passer par WooCommerce jugé disproportionné pour ce seul besoin. La réponse tient dans la façon dont Stripe Elements est monté et dont les erreurs sont restituées.
Ce tutoriel construit un bloc dynamique don/formulaire-paiement qui embarque Stripe Elements pour la saisie de carte bancaire, avec une attention constante à la navigation clavier et aux messages d’erreur. Il ne traite pas des paiements récurrents (voir Stripe Billing pour ce cas) ni de la facturation automatisée qui pourrait suivre.
Étape 1 — Charger Stripe.js côté front uniquement
Le script Stripe.js doit être chargé uniquement sur les pages où le bloc est présent, jamais globalement. Dans le fichier PHP du bloc, on détecte sa présence avec has_block() avant d’enregistrer la dépendance :
function don_enqueue_stripe_assets() {
if ( has_block( 'don/formulaire-paiement' ) ) {
wp_enqueue_script(
'stripe-js',
'https://js.stripe.com/v3/',
array(),
null,
true
);
wp_enqueue_script(
'don-bloc-paiement',
plugins_url( 'build/view.js', __FILE__ ),
array( 'stripe-js' ),
'1.0.0',
true
);
}
}
add_action( 'wp_enqueue_scripts', 'don_enqueue_stripe_assets' );
Étape 2 — Monter les Elements avec un focus initial maîtrisé
Stripe Elements injecte ses champs dans des iframe internes, ce qui complique la gestion du focus depuis le code du bloc. Au montage, il faut explicitement donner le focus au premier champ, plutôt que de laisser le comportement par défaut du navigateur décider :
const stripe = Stripe( DON_PAIEMENT_CONFIG.clePublique );
const elements = stripe.elements();
const numeroCarte = elements.create( 'cardNumber', {
style: styleAccessible,
} );
numeroCarte.mount( '#don-carte-numero' );
numeroCarte.on( 'ready', () => numeroCarte.focus() );

Le style transmis à elements.create() mérite une attention particulière : Stripe applique par défaut un contraste de texte parfois trop faible, et surtout n’affiche aucun indicateur de focus visible dans l’iframe. Il faut le définir explicitement via l’option style.base et vérifier le rendu final au clavier, pas seulement à la souris.
Étape 3 — Restituer les erreurs Stripe en ARIA
Stripe déclenche un événement change sur chaque Element, contenant un objet error quand la saisie est invalide. La difficulté n’est pas de récupérer ce message, mais de le relier correctement au champ concerné pour qu’un lecteur d’écran l’annonce au bon moment.
- Un conteneur
<p id="erreur-carte-numero">reçoit le texte d’erreur retourné par Stripe. - Le champ visuellement associé (le label, pas l’iframe elle-même) porte
aria-describedby="erreur-carte-numero". - Le conteneur d’erreur porte
role="alert"pour une annonce immédiate, sans attendre un changement de focus.
numeroCarte.on( 'change', ( event ) => {
const zone = document.getElementById( 'erreur-carte-numero' );
zone.textContent = event.error ? event.error.message : '';
} );
Étape 4 — Gérer la soumission et le focus sur erreur
À la soumission, si Stripe retourne une erreur sur la confirmation de paiement, le focus doit revenir sur le premier champ concerné plutôt que de rester bloqué sur le bouton de validation. Un utilisateur clavier qui vient de cliquer sur « Valider mon don » et qui n’a aucun retour de focus perd totalement le fil de ce qui s’est passé.
| Situation | Comportement attendu |
|---|---|
| Numéro de carte invalide | Focus renvoyé sur cardNumber, message lu par le lecteur d’écran |
| Carte refusée par la banque | Message général en haut du formulaire, focus déplacé dessus |
| Succès du paiement | Focus déplacé vers le message de confirmation, pas de redirection muette |
Étape 5 — Vérifier avec un test clavier complet
Le test final consiste à parcourir tout le formulaire à la tabulation seule : nom, numéro de carte, date d’expiration, CVC, bouton de validation, puis à provoquer volontairement une erreur (numéro invalide) pour vérifier que le focus et l’annonce vocale suivent bien la logique décrite plus haut.
Un formulaire de paiement accessible au clavier n’est pas un formulaire qui fonctionne au clavier par accident : c’est un formulaire où chaque transition de focus a été écrite intentionnellement.
Pour aller plus loin
Cette approche reste valable pour d’autres intégrations de paiement embarquées dans un bloc dynamique, dès lors que le prestataire externe injecte ses propres champs dans une iframe : le principe (focus maîtrisé, erreurs en ARIA, focus post-erreur) ne change pas, seule l’API change. La documentation officielle Stripe Elements détaille les événements disponibles sur chaque type de champ, à consulter avant toute personnalisation poussée du style.