> ## Documentation Index
> Fetch the complete documentation index at: https://docs.qaos.machdel.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Formulaires

> Critères liés à l'utilisabilité des formulaires : messages d'erreur manquants, retour de validation invisible, champs obligatoires non étiquetés et associations d'erreurs inaccessibles.

Les critères d'utilisabilité des formulaires frustrent les utilisateurs et entraînent des abandons. Les critères d'accessibilité dans les formulaires les rendent complètement inutilisables pour les utilisateurs de lecteurs d'écran. Les deux catégories ont un impact direct sur les affaires.

***

## missing-error-messages

<Badge>Critique</Badge> WCAG 3.3.1

**Description**

Lorsqu'un formulaire est soumis avec des données invalides ou manquantes, aucun message d'erreur n'est affiché nulle part dans le DOM. La soumission échoue silencieusement, laissant les utilisateurs sans indication de ce qui s'est mal passé ou comment corriger.

**Importance**

Sans retour d'erreur, les utilisateurs ne peuvent pas compléter le formulaire. Cela bloque directement l'accomplissement des tâches pour tous les utilisateurs, et pour les utilisateurs de lecteurs d'écran, même un message d'erreur générique est critique car ils ne peuvent pas analyser visuellement le formulaire pour les indicateurs d'erreur visuels.

**Comment QAOS le détecte**

L'agent soumet des formulaires avec des champs obligatoires laissés vides ou avec des données invalides, puis analyse le DOM pour tout élément de message d'erreur, y compris les messages dans des éléments `<div>` séparés, les attributs `data-validation-message` ou les régions ARIA live.

**Exemples**

```html theme={null}
<!-- Formulaire sans gestion des erreurs, échoue silencieusement -->
<form>
  <input type="email" required name="email">
  <button type="submit">S'abonner</button>
</form>
<!-- Après une soumission invalide : page inchangée, aucun message affiché -->
```

**Comment corriger**

Affichez au moins un message d'erreur lorsque la validation du formulaire échoue. Le message doit indiquer quels champs sont invalides et ce que l'utilisateur doit faire :

```html theme={null}
<!-- Erreur de résumé générique -->
<div role="alert" id="form-errors">
  Veuillez corriger les erreurs suivantes avant de continuer.
</div>

<!-- Erreur inline par champ -->
<label for="email">Email</label>
<input type="email" id="email" aria-describedby="email-error">
<span id="email-error" role="alert">Veuillez saisir une adresse email valide</span>
```

***

## error-not-visible

<Badge>Critique</Badge> WCAG 3.3.1

**Description**

Des éléments de message d'erreur existent dans le DOM après une soumission échouée, mais ils sont masqués via CSS (`display: none`, `visibility: hidden`, `opacity: 0` ou positionnement hors écran) et n'apparaissent jamais à l'utilisateur.

**Importance**

Il s'agit d'un état d'échec particulièrement déroutant : l'application génère des informations d'erreur mais les supprime. Les utilisateurs ne voient rien, n'ont aucun moyen de corriger leur saisie et ne peuvent pas compléter le formulaire.

**Comment QAOS le détecte**

Après avoir soumis un formulaire avec des données invalides, l'agent vérifie si des éléments liés aux erreurs existent dans le DOM mais sont masqués par des propriétés CSS qui les empêchent d'être visibles.

**Comment corriger**

Assurez-vous que les éléments de message d'erreur sont visibles lorsque la validation échoue :

```css theme={null}
/* Au lieu de basculer display:none */
.error-message {
  display: block; /* Afficher lors d'une erreur */
}

/* Ou utiliser visibility */
.field-error {
  visibility: visible;
  height: auto;
}
```

Utilisez JavaScript ou la réactivité du framework pour afficher conditionnellement les messages d'erreur plutôt que de masquer ceux pré-rendus :

```javascript theme={null}
// Exemple React
{errors.email && <span role="alert">{errors.email.message}</span>}
```

***

## required-field-not-marked

<Badge>Moyen</Badge> WCAG 3.3.2

**Description**

Les champs de formulaire qui sont obligatoires (via l'attribut `required` ou la validation côté serveur) ne sont pas visuellement indiqués comme obligatoires : pas d'astérisque, pas d'étiquette, pas d'indice visuel qui aide les utilisateurs à comprendre quels champs doivent être remplis avant la soumission.

**Importance**

Les utilisateurs qui ne réalisent pas qu'un champ est obligatoire le sautent souvent, rencontrent des erreurs de validation et se sentent frustrés. Des indicateurs clairs de champs obligatoires réduisent l'abandon de formulaires.

**Comment QAOS le détecte**

L'agent identifie les `<input required>` ou les champs validés qui manquent d'indicateur visuel (astérisque dans l'étiquette, texte « obligatoire » ou convention similaire).

**Exemples**

```html theme={null}
<!-- Indicateur visuel obligatoire manquant -->
<label for="phone">Téléphone</label>
<input type="tel" id="phone" required>

<!-- Correct : indicateur astérisque -->
<label for="phone">Téléphone <span aria-hidden="true">*</span></label>
<input type="tel" id="phone" required aria-required="true">

<!-- Inclure une légende expliquant l'indicateur -->
<p>Les champs marqués d'un <span aria-hidden="true">*</span> sont obligatoires.</p>
```

**Comment corriger**

Marquez les champs obligatoires visuellement avec un indicateur cohérent (typiquement `*`). Incluez une légende près du haut du formulaire expliquant la convention. Utilisez `aria-required="true"` sur le champ de saisie pour les utilisateurs de lecteurs d'écran.

***

## error-not-associated

<Badge>Faible</Badge> WCAG 1.3.1

**Description**

Des messages d'erreur sont affichés après une soumission échouée mais ne sont pas liés programmatiquement au champ qu'ils décrivent. Le message apparaît visuellement près du champ mais manque de liaison `aria-describedby` ou `aria-errormessage`.

**Importance**

Les lecteurs d'écran annoncent les champs de saisie en lisant leur étiquette et toute description programmatiquement associée. Sans `aria-describedby`, un utilisateur de lecteur d'écran se concentrant sur un champ n'entendra pas le message d'erreur associé à moins qu'il ne navigue pour le trouver.

**Comment QAOS le détecte**

Après avoir soumis des données invalides, l'agent vérifie si les champs avec des messages d'erreur visibles ont des attributs `aria-describedby` ou `aria-errormessage` correspondants pointant vers l'élément d'erreur.

**Comment corriger**

Liez les messages d'erreur à leurs champs en utilisant `aria-describedby` :

```html theme={null}
<label for="email">Email</label>
<input
  type="email"
  id="email"
  aria-describedby="email-error"
  aria-invalid="true"
>
<span id="email-error" role="alert">
  Veuillez saisir une adresse email valide
</span>
```

***

## placeholder-as-label

<Badge>Moyen</Badge> WCAG 1.3.1

**Description**

Un champ de saisie dépend uniquement du texte d'espace réservé pour communiquer son purpose. Il n'y a pas d'élément `<label>` visible, d'attribut `aria-label` ou `aria-labelledby` associé au champ.

**Importance**

Le texte d'espace réservé disparaît dès que l'utilisateur commence à taper, laissant le champ sans étiquette du tout. Les utilisateurs qui reviennent à un formulaire partiellement rempli voient des champs sans étiquette et ne se souviennent pas de ce qu'ils ont saisi. Les lecteurs d'écran gèrent également les espaces réservés de manière inconsistante : certains les annoncent, d'autres non.

**Comment QAOS le détecte**

L'agent identifie les champs de saisie qui ont un attribut placeholder mais aucune association d'étiquette programmatique.

**Exemples**

```html theme={null}
<!-- Placeholder uniquement, l'étiquette disparaît lors de la frappe -->
<input type="email" placeholder="Adresse email">

<!-- Correct : étiquette visible + placeholder comme indice -->
<label for="email">Adresse email</label>
<input type="email" id="email" placeholder="vous@example.com">
```

**Comment corriger**

Fournissez toujours une étiquette visible persistante. Utilisez le texte d'espace réservé uniquement comme indice supplémentaire, jamais comme étiquette principale.

***

## form-no-submit-button

<Badge>Moyen</Badge>

**Description**

Un élément de formulaire ne contient pas de bouton de soumission visible ou équivalent (`<button type="submit">` ou `<input type="submit">`), rendant impossible la soumission via le clavier sans dépendre de la touche Entrée dans un champ de texte.

**Importance**

Les utilisateurs au clavier uniquement et les utilisateurs de technologies d'assistance s'attendent à une action clairement étiquetée pour soumettre un formulaire. Un formulaire sans bouton de soumission est également non standard et peut dérouter les utilisateurs qui ne connaissent pas le raccourci Entrée.

**Comment QAOS le détecte**

L'agent analyse les éléments de formulaire pour l'absence de tout bouton de soumission ou contrôle interactif équivalent qui soumettrait le formulaire.

**Comment corriger**

Chaque formulaire doit avoir un bouton de soumission explicite :

```html theme={null}
<form>
  <label for="email">Email</label>
  <input type="email" id="email" name="email">
  <button type="submit">S'abonner</button>
</form>
```

***

## select-missing-label

<Badge>Moyen</Badge> WCAG 1.3.1

**Description**

Un élément `<select>` n'a pas d'étiquette associée : ni `<label for="...">`, `aria-label` ni `aria-labelledby`, rendant son purpose opaque pour les lecteurs d'écran.

**Importance**

Les lecteurs d'écran annoncent les contrôles de formulaire en lisant leur étiquette. Un `<select>` sans étiquette est annoncé seulement comme « combo box » ou « list box » sans indication de ce que l'utilisateur sélectionne.

**Comment QAOS le détecte**

L'agent analyse le DOM pour les éléments `<select>` sans étiquette programmatiquement associée.

**Exemples**

```html theme={null}
<!-- Select sans étiquette -->
<select name="country">
  <option>États-Unis</option>
</select>

<!-- Correct : étiquette associée -->
<label for="country">Pays</label>
<select id="country" name="country">
  <option>États-Unis</option>
</select>
```

**Comment corriger**

Associez chaque `<select>` à une étiquette visible via `<label for="...">`. Si une étiquette visible n'est pas possible, utilisez `aria-label` :

```html theme={null}
<select aria-label="Sélectionnez votre pays" name="country">
```

***

## copy-paste-blocked

<Badge>Moyen</Badge>

**Description**

Un champ de saisie (généralement un champ de confirmation de mot de passe ou de code OTP) bloque les opérations de collage, forçant les utilisateurs à taper le contenu manuellement même quand ils l'ont copié dans le presse-papiers.

**Importance**

Bloquer le collage décourage l'utilisation des gestionnaires de mots de passe (qui collent des mots de passe forts et uniques), force les utilisateurs à retaper des identifiants complexes (augmentant les erreurs) et n'offre aucun avantage de sécurité réel. Les directives NIST recommandent explicitement d'autoriser le collage dans les champs de mot de passe.

**Comment QAOS le détecte**

L'agent tente de coller dans les champs de saisie via le clavier et des méthodes programmatiques et vérifie si le collage est supprimé.

**Comment corriger**

Supprimez tout `onpaste="return false"` ou écouteur d'événement `paste` qui appelle `preventDefault()` :

```javascript theme={null}
// Supprimer ceci
input.addEventListener('paste', (e) => e.preventDefault())

// Autoriser le collage : c'est le comportement par défaut, aucun code nécessaire
```

***

## input-missing-type

<Badge>Faible</Badge>

**Description**

Un élément `<input>` n'a pas d'attribut `type`. Le navigateur utilise par défaut `type="text"`, ce qui peut ne pas correspondre au type de données attendu, manquant les avantages sémantiques comme les claviers numériques sur mobile et la validation intégrée.

**Comment QAOS le détecte**

L'agent analyse le DOM pour les éléments `<input>` sans attribut `type`.

**Exemples**

```html theme={null}
<!-- Type manquant, par défaut "text" -->
<input name="email">
<input name="age">

<!-- Correct : types explicites -->
<input type="email" name="email">
<input type="number" name="age" min="0" max="150">
```

**Comment corriger**

Définissez toujours un attribut `type` explicite sur chaque champ de saisie pour obtenir le bon clavier sur mobile, la validation intégrée du navigateur et une signification sémantique claire.

***

## missing-autocomplete

<Badge>Faible</Badge> WCAG 1.3.5

**Description**

Les champs de données personnelles (nom, email, numéro de téléphone, adresse) n'ont pas l'attribut `autocomplete`, empêchant les navigateurs et les gestionnaires de mots de passe de les remplir automatiquement.

**Importance**

L'autocomplétion fait gagner un temps considérable aux utilisateurs, en particulier ceux ayant des handicaps moteurs qui trouvent la frappe difficile. Elle améliore également la précision en réduisant les erreurs de saisie manuelle.

**Comment QAOS le détecte**

L'agent analyse les champs de formulaire pour les saisies de données personnelles (par nom, type ou texte d'étiquette) qui manquent de l'attribut `autocomplete`.

**Comment corriger**

Ajoutez le jeton `autocomplete` approprié aux champs de données personnelles :

```html theme={null}
<input type="text" name="name" autocomplete="name">
<input type="email" name="email" autocomplete="email">
<input type="tel" name="phone" autocomplete="tel">
<input type="text" name="address" autocomplete="street-address">
```

***

## password-no-visibility-toggle

<Badge>Faible</Badge>

**Description**

Un champ de saisie de mot de passe n'a pas de bouton afficher/masquer, rendant impossible pour les utilisateurs de vérifier ce qu'ils ont tapé sans outils externes.

**Importance**

Le masquage du mot de passe entraîne des erreurs de frappe. Sans bouton de visibilité, les utilisateurs ne peuvent pas vérifier leur mot de passe, ce qui entraîne des échecs de connexion ou des champs de confirmation de mot de passe non concordants. C'est un problème d'utilisabilité courant qui décourage l'utilisation de mots de passe forts.

**Comment QAOS le détecte**

L'agent analyse le DOM pour les éléments `<input type="password">` et vérifie si un bouton de bascule leur est associé.

**Comment corriger**

Ajoutez un bouton de bascule qui change le type de saisie entre `type="password"` et `type="text"` :

```html theme={null}
<div class="password-field">
  <input type="password" id="password" name="password">
  <button type="button" aria-label="Afficher le mot de passe" onclick="togglePassword()">
    Afficher
  </button>
</div>
```

```javascript theme={null}
function togglePassword() {
  const input = document.getElementById('password')
  input.type = input.type === 'password' ? 'text' : 'password'
}
```

***

## character-count-missing

<Badge>Faible</Badge>

**Description**

Un champ de texte ou une zone de texte avec une limite de caractères (`maxlength`) n'affiche pas de compteur de caractères visible ni d'indicateur de caractères restants, laissant les utilisateurs ignorants de la limite jusqu'à ce qu'ils l'atteignent.

**Comment QAOS le détecte**

L'agent identifie les éléments `<input>` ou `<textarea>` avec un attribut `maxlength` et vérifie si un compteur de caractères est visible près du champ.

**Comment corriger**

Affichez un compteur de caractères en direct qui se met à jour au fur et à mesure que l'utilisateur tape :

```html theme={null}
<textarea id="bio" maxlength="280"></textarea>
<span id="bio-count" aria-live="polite">280 caractères restants</span>
```

```javascript theme={null}
document.getElementById('bio').addEventListener('input', function () {
  const remaining = 280 - this.value.length
  document.getElementById('bio-count').textContent = `${remaining} caractères restants`
})
```

***

## ambiguous-date-format

<Badge>Faible</Badge>

**Description**

Les dates sont affichées ou attendues dans un format ambigu (tel que `01/02/2024`) qui peut être interprété différemment selon la locale (MM/JJ ou JJ/MM).

**Importance**

Une date comme `04/05/24` signifie le 5 avril aux États-Unis et le 4 mai en Europe. Les dates ambiguës entraînent des erreurs de réservation, des délais manqués et de la confusion pour les utilisateurs dans des contextes internationaux.

**Comment QAOS le détecte**

L'agent analyse les textes d'affichage de dates et les espaces réservés des champs de date pour les formats de dates numériques sans structure non ambiguë.

**Comment corriger**

Utilisez des formats de date non ambigus qui ne dépendent pas des conventions locales :

```
Ambigu : 01/02/2024
Clair :  2 janv. 2024  |  2 janvier 2024  |  2024-01-02 (ISO 8601)
```

Pour les saisies de date, utilisez `<input type="date">` (le navigateur affiche un sélecteur adapté à la locale) ou incluez une étiquette de format explicite :

```html theme={null}
<label for="dob">Date de naissance (JJ/MM/AAAA)</label>
<input type="text" id="dob" placeholder="15/06/1990">
```

***

## empty-state-missing

<Badge>Faible</Badge>

**Description**

Une liste de contenu dynamique (telle qu'une section de commentaires, une boîte de réception, un panneau de notifications ou des résultats de recherche) est vide et n'affiche qu'un espace blanc sans message expliquant l'état vide.

**Importance**

Un espace blanc là où du contenu est attendu ressemble à un échec de chargement ou un bug d'affichage. Les utilisateurs ne savent pas si la liste est véritablement vide, encore en chargement ou défectueuse. Un message explicite « Aucun résultat » ou « Votre boîte de réception est vide » supprime l'ambiguïté.

**Comment QAOS le détecte**

L'agent vérifie les conteneurs de liste (`<ul>`, `<ol>` ou régions de contenu étiquetées) qui n'ont pas d'éléments enfants et aucun texte explicatif adjacent.

**Comment corriger**

Affichez un message d'état vide clair et utile lorsqu'une liste dynamique est vide :

```jsx theme={null}
{comments.length === 0 ? (
  <p>Aucun commentaire pour l'instant. Soyez le premier à en laisser un !</p>
) : (
  <ul>{comments.map(c => <CommentItem key={c.id} {...c} />)}</ul>
)}
```
