Tips & Tricks (Mis à jour: 02/06/2026)

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.

Accessibilité avec Claude Code : HTML sémantique, ARIA, axe et vérification

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.

ZoneCritère pratiqueÉchec fréquent
HTML sémantiqueUtiliser button, a, form, label, main, nav selon leur rôleUn div cliquable remplace un contrôle natif
ClavierTab, Shift+Tab, Enter, Space et Escape couvrent le flux principalLe modal se ferme seulement à la souris
FocusLe focus entre dans l’UI ouverte et revient au déclencheurLe focus part derrière le dialogue
ARIAAjouter ARIA seulement si HTML ne suffit pasaria-label masque l’absence de label visible
CouleurTexte, contrôles, erreurs et focus restent visiblesL’erreur dépend seulement du rouge
FormulaireLabels, aides, état invalide et erreurs sont liés aux champsL’erreur est visible mais non annoncée
Testsaxe plus clavier et lecteur d’écranZé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.

#Claude Code #accessibility #WCAG #a11y #React
Gratuit

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.

Masa

À propos de l'auteur

Masa

Ingénieur spécialisé dans les workflows pratiques avec Claude Code.