Accessibilité avec Claude Code : HTML sémantique, ARIA, axe et vérification
Workflow Claude Code pour accessibilité : HTML, clavier, formulaires, focus, axe et lecteur d’écran.
L’accessibilité ne consiste pas à lancer un outil juste avant la mise en ligne. Elle commence avec le HTML sémantique, continue avec la navigation au clavier, la gestion du focus, les erreurs de formulaire, le contraste des couleurs, puis se termine par des tests automatiques et une vérification humaine au lecteur d’écran.
Claude Code peut accélérer ce travail, mais seulement si la demande est précise. Un simple “rends ce composant accessible” peut produire un div enrichi avec ARIA sans comportement clavier, un modal qui semble correct mais laisse le focus derrière lui, ou des erreurs visibles que le lecteur d’écran n’annonce pas.
Les références utilisées ici sont officielles : W3C WCAG 2.2 pour la cible pratique, le WAI-ARIA Authoring Practices Guide pour les patterns, MDN ARIA pour la règle “HTML sémantique d’abord”, la documentation axe-core de Deque pour l’automatisation, et la documentation officielle Claude Code pour l’outil.
Fixer le niveau attendu
“Améliorer l’accessibilité” est trop vague. Donne à Claude Code une cible mesurable : WCAG 2.2 AA comme objectif pratique, HTML sémantique avant ARIA, parcours principal utilisable au clavier, focus visible, erreurs compréhensibles, puis preuve par test automatique et vérification manuelle.
| Zone | Critère pratique | Échec fréquent |
|---|---|---|
| HTML sémantique | Utiliser button, a, form, label, main, nav selon leur rôle | Un div cliquable remplace un contrôle natif |
| Clavier | Tab, Shift+Tab, Enter, Space et Escape couvrent le flux principal | Le modal se ferme seulement à la souris |
| Focus | Le focus entre dans l’UI ouverte et revient au déclencheur | Le focus part derrière le dialogue |
| ARIA | Ajouter ARIA seulement si HTML ne suffit pas | aria-label masque l’absence de label visible |
| Couleur | Texte, contrôles, erreurs et focus restent visibles | L’erreur dépend seulement du rouge |
| Formulaire | Labels, aides, état invalide et erreurs sont liés aux champs | L’erreur est visible mais non annoncée |
| Tests | axe plus clavier et lecteur d’écran | Zéro violation automatique devient une fausse preuve complète |
MDN rappelle qu’un élément HTML natif doit être préféré s’il fournit déjà la sémantique et le comportement nécessaires. Claude Code doit donc corriger la structure avant d’ajouter des états ARIA.
Prompt sûr pour Claude Code
Un prompt utile ressemble à un contrat de revue. Il limite le périmètre, protège les éléments business et demande des preuves.
claude <<'PROMPT'
Scope:
- Review only src/components/CheckoutForm.tsx and its tests.
- Do not change pricing copy, analytics events, or unrelated styles.
Accessibility target:
- Use WCAG 2.2 AA as the practical target.
- Prefer semantic HTML before ARIA.
- Add ARIA only when native HTML cannot express the state.
Check these items:
- Labels, descriptions, required state, and validation errors.
- Keyboard operation with Tab, Shift+Tab, Enter, Space, and Escape.
- Focus order, visible focus, and focus return after closing UI.
- Color contrast and non-color error indicators.
- Automated axe check plus manual screen-reader notes.
Output:
- Findings first, with file and line references.
- Minimal patch.
- Commands to verify.
- Any remaining risk.
PROMPT
La ligne importante est Findings first. Claude Code doit expliquer le problème avant d’écrire le patch. C’est essentiel pour une page de produit ou un formulaire de consultation où un refactoring large peut casser une URL Gumroad, un événement analytics ou un CTA. Le même principe de périmètre réduit est détaillé dans les astuces de productivité Claude Code.
Cas 1 : CTA produit ou CTA d’article
Un CTA de produit est une zone de conversion. S’il déclenche une navigation, il doit être un lien réel, pas une carte entière avec onclick.
<div class="hero-card" onclick="location.href='/en/products'">
<div class="title">Claude Code Templates</div>
<div class="button">Buy now</div>
</div>
Une version plus robuste restaure la structure : titre, description et destination explicite.
<section aria-labelledby="templates-heading" class="product-cta">
<h2 id="templates-heading">Réduire les revues avec des modèles Claude Code</h2>
<p>
Copiez des prompts réutilisables pour l’implémentation,
la revue, le débogage et la documentation.
</p>
<a class="primary-link" href="/en/products">
Voir les ressources produit
</a>
</section>
Demande à Claude Code de préserver les liens, les attributs de tracking et le texte de conversion. Une correction accessible qui supprime le bon CTA reste une régression produit.
Cas 2 : formulaire de contact ou de consultation
Un formulaire mal étiqueté bloque autant l’accessibilité que la conversion. L’utilisateur doit comprendre le champ, le format attendu, l’erreur et la correction à faire.
import { FormEvent, useState } from "react";
type Errors = {
name?: string;
email?: string;
};
export function ConsultationForm() {
const [errors, setErrors] = useState<Errors>({});
function handleSubmit(event: FormEvent<HTMLFormElement>) {
event.preventDefault();
const data = new FormData(event.currentTarget);
const nextErrors: Errors = {};
if (!String(data.get("name") || "").trim()) {
nextErrors.name = "Indiquez votre nom.";
}
if (!String(data.get("email") || "").includes("@")) {
nextErrors.email = "Indiquez une adresse e-mail valide.";
}
setErrors(nextErrors);
}
return (
<form aria-labelledby="consultation-title" onSubmit={handleSubmit} noValidate>
<h2 id="consultation-title">Demande de consultation</h2>
<div className="field">
<label htmlFor="name">Nom</label>
<input
id="name"
name="name"
autoComplete="name"
aria-invalid={errors.name ? "true" : "false"}
aria-describedby={errors.name ? "name-error" : undefined}
/>
{errors.name && (
<p id="name-error" role="alert">
{errors.name}
</p>
)}
</div>
<div className="field">
<label htmlFor="email">E-mail</label>
<p id="email-help">Utilisez une adresse où nous pouvons répondre.</p>
<input
id="email"
name="email"
type="email"
autoComplete="email"
aria-invalid={errors.email ? "true" : "false"}
aria-describedby={
errors.email ? "email-help email-error" : "email-help"
}
/>
{errors.email && (
<p id="email-error" role="alert">
{errors.email}
</p>
)}
</div>
<button type="submit">Envoyer la demande</button>
</form>
);
}
Le piège courant est d’afficher l’erreur sans la relier au champ. L’autre piège consiste à référencer un ID d’erreur qui n’existe pas encore. Relie l’aide permanente tout le temps, puis l’erreur seulement quand elle est rendue.
Cas 3 : modal, palette de commandes et menu
Le modal est le composant que Claude Code produit souvent “joli mais incomplet”. Le pattern officiel Dialog Modal indique que le focus doit entrer dans le dialogue, rester dans la séquence Tab, se fermer avec Escape et revenir au bouton déclencheur.
import { ReactNode, useEffect, useRef } from "react";
type ModalProps = {
open: boolean;
title: string;
onClose: () => void;
children: ReactNode;
};
const focusableSelector = [
"a[href]",
"button:not([disabled])",
"input:not([disabled])",
"select:not([disabled])",
"textarea:not([disabled])",
'[tabindex]:not([tabindex="-1"])',
].join(",");
export function AccessibleModal(props: ModalProps) {
const { open, title, onClose, children } = props;
const dialogRef = useRef<HTMLDivElement>(null);
const previousFocusRef = useRef<HTMLElement | null>(null);
useEffect(() => {
if (!open) return;
previousFocusRef.current = document.activeElement as HTMLElement;
const focusable = dialogRef.current?.querySelectorAll<HTMLElement>(
focusableSelector
);
focusable?.[0]?.focus();
function onKeyDown(event: KeyboardEvent) {
if (event.key === "Escape") onClose();
if (event.key !== "Tab" || !dialogRef.current) return;
const items = [...dialogRef.current.querySelectorAll<HTMLElement>(
focusableSelector
)];
const first = items[0];
const last = items[items.length - 1];
if (event.shiftKey && document.activeElement === first) {
event.preventDefault();
last?.focus();
} else if (!event.shiftKey && document.activeElement === last) {
event.preventDefault();
first?.focus();
}
}
document.addEventListener("keydown", onKeyDown);
return () => {
document.removeEventListener("keydown", onKeyDown);
previousFocusRef.current?.focus();
};
}, [open, onClose]);
if (!open) return null;
return (
<div className="modal-backdrop">
<div
ref={dialogRef}
role="dialog"
aria-modal="true"
aria-labelledby="modal-title"
className="modal-panel"
>
<h2 id="modal-title" tabIndex={-1}>
{title}
</h2>
{children}
<button type="button" onClick={onClose}>
Fermer
</button>
</div>
</div>
);
}
Pour un menu, vérifie d’abord le besoin réel. Le Menu Button Pattern convient aux menus de commandes. Une navigation classique est souvent plus accessible avec nav et une liste de liens.
Couleur, focus et mobile
La régression classique est outline: none sans remplacement. Les erreurs ne doivent pas dépendre uniquement de la couleur.
.primary-link {
background: #0f766e;
border-radius: 6px;
color: #ffffff;
display: inline-flex;
font-weight: 700;
min-height: 44px;
padding: 0.75rem 1rem;
}
.primary-link:focus-visible,
button:focus-visible,
input:focus-visible {
outline: 3px solid #f59e0b;
outline-offset: 3px;
}
.field [role="alert"] {
border-left: 4px solid #b91c1c;
color: #7f1d1d;
margin-top: 0.5rem;
padding-left: 0.75rem;
}
Vérifie aussi le mobile : bouton de fermeture trop petit, focus caché sous un header fixe, CTA trop étroit. Ces problèmes ne se voient pas toujours dans une revue desktop.
axe et vérification manuelle
axe trouve vite les problèmes structurels. Il ne garantit pas que le libellé soit clair, que l’ordre de lecture soit logique ou que le parcours métier soit compréhensible.
npm install -D @axe-core/playwright @playwright/test
npx playwright install --with-deps chromium
import AxeBuilder from "@axe-core/playwright";
import { expect, test } from "@playwright/test";
test("consultation form has no serious accessibility issues", async ({ page }) => {
await page.goto("/contact");
const results = await new AxeBuilder({ page })
.include("main")
.withTags(["wcag2a", "wcag2aa", "wcag22aa"])
.analyze();
expect(results.violations).toEqual([]);
});
La vérification manuelle doit commencer par les parcours à risque : CTA produit, formulaire, checkout, modal, navigation et correction d’erreur. NVDA est pratique sous Windows. VoiceOver est disponible par défaut sous macOS.
Échecs concrets à demander à Claude Code
role="button"sans support Enter et Space.- Bouton icône sans nom accessible.
- Texte alternatif inutile comme
alt="image". aria-hidden="true"qui cache le modal ou une région live.- Erreur visible sans
aria-describedby. - Focus visuel supprimé sans remplacement.
- Modal qui ne rend pas le focus au déclencheur.
- Test automatique limité à la page marketing, pas au vrai formulaire.
Colle cette liste dans Claude Code après le patch et demande les fichiers et lignes concernés. C’est plus fiable qu’un simple “revérifie”.
CTA et résultat vérifié
Pour transformer cette méthode en routine, commence par les ressources Claude Code. Si tu réutilises souvent les mêmes revues, les 50 modèles de prompts Claude Code évitent de repartir de zéro. Pour un déploiement d’équipe avec permissions, hooks et preuves de vérification, passe par la consultation.
Pour cette mise à jour, j’ai vérifié trois échecs fréquents : une carte CTA en div cliquable, un formulaire dont les erreurs n’étaient pas annoncées et un modal qui ne rendait pas le focus. Le flux le plus stable avec Claude Code a été : findings d’abord, patch minimal ensuite, puis contrôle clavier et VoiceOver. axe a aidé, mais la compréhension réelle du parcours s’est vérifiée à l’écoute.
PDF gratuit: cheatsheet Claude Code
Saisissez votre email et téléchargez une page avec commandes, habitudes de review et workflow sûr.
Nous protégeons vos données et n'envoyons pas de spam.
À propos de l'auteur
Masa
Ingénieur spécialisé dans les workflows pratiques avec Claude Code.
Articles liés
Échelle de sécurité des permissions Claude Code
Passer du read-only aux éditions limitées, preuves et checks de déploiement sans perdre le contrôle.
Claude Code Small PR Proof Pack : rendre les petits changements reviewables
Un pack de preuve pour PR Claude Code : diff, vérifications, URL publique, CTA et rollback.
Gate de review avant commit avec Claude Code
Review avant commit avec Claude Code : diff, build, URL publique, liens Gumroad, CTA consultation, tests manquants et fichiers hors scope.