Exemples de formulaire
Préambule
Pour qu’un formulaire soit accessible à l’ensemble des utilisateurs, quelques règles doivent être respectées lors du développement. C’est ce que nous allons voir en détail dans l’exemple de formulaire accessible.
Exemple de formulaire accessible
Dans cet exemple, nous avons utilisé la librairie Boosted. Celle-ci permet d’obtenir des formulaires dont le design est conforme à la charte Orange. Nous utilisons également du javascript pour les contrôles de saisie.
Mise en place
Étiqueter les champs de formulaire
Tous les éléments de formulaire doivent être étiquetés avec un libellé pertinent, donc qui, spécifiquement, informe sur le contenu attendu dans le champ, le bouton, le bouton radio la case à cocher ou la liste déroulante. Ainsi, le lecteur d’écran vocalisera automatiquement le libellé du champ de formulaire lors de la sélection de l'élément de formulaire lors de la navigation.
De plus, les étiquettes (label
) doivent être le moins possible éloignées visuellement de leur champ afin de faciliter leur association (notamment par les malvoyants, déficients cognitifs, les utilisateurs ayant des troubles de l'attention ou de la concentration).
Il existe plusieurs solutions pour étiqueter un champ de formulaire (autre qu'un bouton).
Utilisation d’une balise label
Il s’agit de la solution standard, à utiliser en priorité, pour étiqueter un champ de formulaire, la mieux supportée par les outils d’assistance.
Utiliser une balise label
et renseigner son attribut for
avec l’id
du champ de formulaire auquel elle est associée. C’est important pour les utilisateurs de lecteurs d’écran, mais cela permet également d’améliorer l’ergonomie du formulaire. En effet, lorsque le label est correctement associé à son champ de formulaire, il devient possible de cocher une case à cocher ou de sélectionner un bouton radio en cliquant directement sur son label et vu la taille par défaut de ces éléments, c'est bien pratique.
<input type="checkbox" id="cgu">
<label for="cgu">Veuillez accepter les <abbr>CGU</abbr>.</label>
Dans de rares cas, il peut s’avérer qu’il ne soit pas nécessaire d’afficher un libellé car sa fonction est grâce au contexte, évidente (champ de recherche proche du bouton avec l'icône loupe, la case à cocher pour sélectionner une ligne de tableau, par exemple). Prévoir tout de même un libellé pour les lecteurs d’écran et le masquer en utilisant une des 3 méthodes suivantes.
Classe CSS de masquage accessible
C’est la méthode utilisée sur le second champ de saisie de l’adresse dans cet exemple de formulaire accessible
(utilisation de la classe visually-hidden
de Bootstrap/Boosted).
Code CSS
.visually-hidden {
position: absolute;
width: 1px;
height: 1px;
padding: 0;
margin: -1px;
overflow: hidden;
clip: rect(0, 0, 0, 0);
white-space: nowrap; /* added line */
border: 0;
}
Code HTML
<label for="adresse">Adresse *</label>
<input name="adresse" data-displayname="adresse" class="form-control" id="adresse" aria-required="true" type="text">
<label class="visually-hidden" for="complement">Complément d’adresse</label>
<input class="form-control" id="complement" type="text">
L’utilisation du masquage accessible permet de masquer l’élément à l’écran tout en conservant sa vocalisation par les outils ou technologies d’assistance (AT). Attention, ne pas utiliser du masquage CSS classique (display: none;
ou visibility: hidden;
) car l’élément sera masqué également pour les lecteurs d’écran.
Consultez l’exemple sur le masquage accessible pour plus l’information.
Utilisation d’un attribut title
L’attribut title
n’est pas suffisamment robuste utile pour l’accessibilité sauf dans ce cas précis, en permettant d’étiqueter un champ de formulaire de manière accessible. Il déclenchera également l’affichage d’une info-bulle au survol de l’élément avec la souris, bonne chose pour les déficients cognitifs, les malvoyants.
<input type="text" title="Rechercher dans le catalogue">
À noter : l’attribut title
positionné ailleurs que sur un champ de formulaire (par exemple sur une image) ne fournit aucune garantie que son contenu sera vocalisé par un lecteur d’écran.
Utilisation d’attributs ARIA aria-label
ou aria-labelledby
Les attributs aria-label
et aria-labelledby
peuvent être utilisés pour étiqueter des champs de formulaire et leur support est bon dans les navigateurs et dans les AT récentes :
- L’attribut
aria-labelledby
permet de préciser l’id
d’un élément présent dans le code qui sera utilisé pour étiqueter le champ. - L’attribut
aria-label
permet de préciser directement un label sous forme d’une chaîne de caractères.
<span id="label-adress">Adresse *</span>
<input type="text" aria-labelledby="label-adress">
<input type="text" aria-label="complément d’adresse">
Le placeholder
et le label
L’attribut placeholder
ne peut pas être utilisé à la place d’un label
. En effet :
- le texte du
placeholder
qui s’affiche dans le champ n’est généralement pas assez contrasté ; - il s’efface à la saisie du contenu dans le champ (entraîne des difficultés en cas de déficience cognitive) ;
- le
placeholder
n’est pas toujours lu par les aides techniques ; - il empêche l’utilisateur de vérifier la saisie avant de valider s’il est utilisé à la place du label ;
- il rend les corrections difficiles en cas d’erreur s'il n'existe pas de label affiché ;
- il rend les champs de saisie moins visibles que ceux sans
placeholder
.
En revanche, le placeholder
peut servir de guide, d’aide pour remplir le champ sans que cette
information soit absolument nécessaire (par exemple, proposer une valeur attendue valide) : ne pas hésiter à
l’utiliser pour ce type de besoin.
<div class="mb-3">
<label for="numero-serie">Veuillez saisir le numéro de série *</label>
<input type="text" name="serie" data-displayname="numéro de série" class="form-control" id="numero-serie" aria-describedby="helpblock"
aria-required="true" placeholder="exemple : TS-0000">
</div>
Utilisation de l'attribut autocomplete
Pour tout champ dont le type est listé dans 7. Input
Purposes for User Interface Components, il faut remplir l'attribut autocomplete
du champ avec la
valeur adéquate.
<div class="mb-3">
<label for="lname">Nom de famille :</label>
<input id="lname" type="text" autocomplete="family-name" class="form-control">
<label for="cc-num">Numéro de carte de crédit :</label>
<input type="text" id="cc-num" autocomplete="cc-number" class="form-control">
</div>
Préciser les champs obligatoires
Il faut, bien sûr, clairement indiquer pour tout utilisateur le fait qu’un champ soit obligatoire. Ceci en utilisant un signe distinctif (mention, pictogramme, image, etc.) mais aussi avec un simple texte (par exemple, « obligatoire ») dans le label
du champ. Ajouter, si besoin, une mention au début du formulaire pour indiquer que le symbole ou le pictogramme en question signale un champ obligatoire.
Les champs obligatoires doivent aussi être indiqués dans le code à l’aide de l’attribut HTML5 required
ou de l’attribut ARIA aria-required
notamment pour les déficients visuels. Leur support par les AT est maintenant suffisant pour que l'on utilise indifféremment l'un ou l'autre mais pas les deux en même temps.
<input type="text" name="telephone" required>
<input type="text" name="telephone" aria-required="true">
Cas particulier des radio-boutons obligatoires
Pour indiquer à un utilisateur d'AT qu'une série de radio-boutons est obligatoire, vous pouvez tout à fait ajouter un aria-required="true"
ou un required
sur chacun d'entre eux. Cependant, une autre solution est envisageable, utiliser le role="radiogroup"
sur l'élément contenant les radio-boutons. Ici, on utilise, en plus, un aria-labelledby
afin de donner une étiquette (nom accessible) pertinente à ce radiogroup
.
<p id="radio1-desc">Choisissez une couleur de T-shirt.</p>
<div role="radiogroup" aria-required="true" aria-labelledby="radio1-desc">
<input type="radio" name="radio1" id="radio1-0">
<label for="radio1-0">Votre T-shirt en rouge</label>
<input type="radio" name="radio1" id="radio1-1">
<label for="radio1-1">Votre T-shirt en bleu</label>
</div>
Préciser le type ou le format attendu
Lorsque c’est nécessaire, préciser pour tous les utilisateurs, dans le label
du champ, le type ou le format de la donnée attendu. Pour que cette information soit vocalisée automatiquement par les lecteurs d’écran, vous préférerez mettre ces informations directement dans la balise label
; sinon utiliser un attribut aria-describedby
pour référencer du texte visuellement présent dans la page mais hors du label
.
<div class="mb-3">
<label for="numero-serie">Veuillez saisir le numéro de série *</label>
<input type="text" id="numero-serie" aria-describedby="helpblock" aria-required="true">ll
</div>
<span id="helpblock" class="help-block">Numéro de série commençant par "TS-" suivi de 4 chiffres (exemple: "TS-4521").</span>
L'étiquette visuelle du champ et son nom (accessible)
On peut modifier le nom accessible d'un élément de formulaire, donc ce qui sera restitué aux AT, pour en savoir plus sur le nom accessible en HTML. Cependant, il ne faut pas que des éléments dont on a modifié le nom accessible soit différents de l'étiquette/intitulé affiché car cela empêche leur utilisation pour des AT de commande vocale notamment. Le nom accessible et l'étiquette/intitulé doivent avoir des valeurs identiques ou, au moins, le texte de l'étiquette/intitulé doit commencer par la valeur du nom accessible.
Déplacer le focus automatiquement lors de l'apparition d'un nouveau champ
Il est parfois tentant, lors de l'activation d'un champ spécifique (par exemple, un bouton radio "Autre, précisez..."), de faire apparaître un nouveau champ tout en y mettant le focus automatiquement. C'est problématique en ce qui concerne l'accessibilité à deux égards :
- Tout d'abord, ce champ qui apparaît, suite à l'activation d'un élément de formulaire par l'utilisateur, doit venir se placer dans le code et visuellement juste après l'élément qui l'a déclenché donc doit être l'élément suivant à la navigation clavier. Si il n'est pas positionné juste après le déclencheur, il faut explicitement prévenir l'utilisateur.
- Le focus ne doit pas automatiquement pointer dans ce nouveau champ car c'est imprévisible pour certains utilisateurs. Deux solutions, ne pas pousser automatiquement le focus dans ce champ ou prévenir l'utilisateur avant le déplacement du focus.
Regrouper les informations de même nature
Les champs de même nature doivent être regroupés, si nécessaire (champs ayant la même étiquette ou étiquette
insuffisante à elle seule pour comprendre quelles données entrer), à l’aide d’une balise fieldset
. Le fieldset
doit également posséder comme premier enfant une légende explicite (balise legend
).
Le fieldset/legend
est nécessaire, notamment, lorsque la légende est utile à la compréhension ou l’individualisation (différencier des label
identiques dans un même formulaire) des balises label
incluses dans le fieldset
.
<fieldset>
<legend>Couleur du capot de votre téléphone</legend>
<input type="radio" name="couleur" id="blanc" checked>
<label for="blanc">Blanc</label>
<input type="radio" name="couleur" id="noir">
<label for="noir">Noir</label>
</fieldset>
<fieldset>
<legend>Adresse de livraison</legend>
<label for="nom">Contact</label>
<input type="text" id="nom">
<label for="adresse">Adresse</label>
<input type="text" id="adresse">
<label for="ville">Ville</label>
<input type="text" id="ville">
</fieldset>
<fieldset>
<legend>Adresse de facturation</legend>
<label for="nom1">Contact</label>
<input type="text" id="nom1">
<label for="adresse1">Adresse</label>
<input type="text" id="adresse1">
<label for="ville1">Ville</label>
<input type="text" id="ville1">
</fieldset>
Cas particulier d'une même donnée ventilées dans plusieurs champs
Par exemple, pour entrer une date sous forme de 3 champs, un pour le jour, un pour le mois et un pour l’année, voici une solution possible :
plutôt fieldset / legend + aria-describedby pointant sur id du legend (pour assurer + de support du legend ) ???
<label for="jourNaissance">Date de naissance</label>
<input type="text" id="jourNaissance" aria-label="jour de naissance (JJ)">
<input type="text" id="adresse" aria-label="mois de naissance (MM)">
<input type="text" id="ville" aria-label="année de naissance (AAAA)">
Contrôle de saisie et message d'erreur
Lors de la validation, si des champs obligatoires ne sont pas renseignés, ou si le format de la donnée saisie n’est pas valide, il faut prévenir l’utilisateur.
Modifier le titre de page, le title
Le titre de la page doit refleter le contenu de celle-ci, donc, lorsqu'un formulaire génère des erreurs d'entrée, il faut l'annoncer à l'utilisateur via une modification du title
. Il faut modifier dynamiquement le titre de page pour indiquer que le formulaire est en erreur et le nombre d'erreur commises (par exemple : "4 erreurs dans le formulaire d'inscription - Accueil Orange.com").
Utiliser l’attribut aria-invalid
pour indiquer une erreur de saisie.
Indiquer dans le code les champs en erreur.
<input type="text" name="telephone" aria-invalid="true">
Annoncer dans une bannière que le formulaire est incomplet ou qu'il existe des erreurs
Pour remonter globalement les erreurs, l'impossibilité de valider un formulaire car des champs obligatoires ne sont pas remplis ou tout autre retour général d'erreur suite à l'entrée de données dans un formulaire, la solution à privilégier est un message d'alerte (dit aussi, selon les cas, de statut, d'état ou contextuel) constitué d'une bannière affichée en haut du formulaire, visible, répertoriant le nombre total d'erreurs à corriger, la liste de celle-ci, une identification précise du champ en erreur du type d'erreur (le nom est obligatoire, le numéro téléphone doit contenir 10 chiffres, par exemple) et si besoin des suggestions de corrections (une date valide : 11/02/2022, les numéros de série sont de la forme TS-XXX XXX, par exemple).
Pour ce message d'alerte, le focus doit être mis sur le titre du message (s'il existe, sinon, sur la première erreur de la liste), et chaque erreur doit avoir un lien vers le champ incriminé. De plus, pour que le contenu complet du message soit annoncé aux utilisateur d'AT sans prise de focus, on utilise le rôle ARIA alert
. Ce type de message permet, même aux utilisateurs de technologies d'assistance (AT) d'être notifié du message lors de la non validation du formulaire.
<div role="alert">
<h2>Deux erreurs dans le formulaire</h2>
<ul>
<li>
<a href="#nom" id="nom_error">
Le Nom de famille est un champ obligatoire, merci de le remplir.
</a>
</li>
<li>
<a href="#date" id="date_error">
Le champ Date de naissance doit respecter le format JJ/MM/AAAA, par exemple 13/07/2008.
</a>
</li>
</ul>
</div>
Avertir l’utilisateur au niveau du champ (en ligne) en cas d’erreur de saisie
Si des erreurs de saisie empêchent la validation du formulaire, plutôt que de lister les erreurs au début du formulaire dans une bannière (voir ci-dessus), on peut, pour chaque champ en erreur avertir l’utilisateur localement en ligne. Bien souvent des messages apparaissent à l’écran, cependant par défaut ils ne sont pas vocalisés au lecteur d’écran. Une des solutions consiste à déplacer automatiquement le focus dans le premier champ en erreur. Ceci aura pour effet de faire vocaliser le ou les libellés ou étiquettes du champ de saisie en question dans le ou lesquels le type erreur sera précisé (la date d'inscription est obligatoire, le numéro de sécurité sociale doit contenir 13 chiffres, par exemple) et si besoin des suggestions de corrections (un code valide : 1234-5678, le marquage produit est de la forme 1111-XXX-YYYY, par exemple).
Dans cet exemple de formulaire accessible, les messages d’erreurs sont déclarés comme des label
et sont associés aux champs de saisie. Ainsi, lorsque le focus arrive dans un champ, le lecteur d’écran vocalise le libellé du champ puis le message d’erreur associé.
<label for="numero-serie">Veuillez saisir le numéro de série *</label>
<input aria-invalid="true" class="error" id="numero-serie" aria-describedby="helpblock" aria-required="true" type="text">
<label for="numero-serie" class="error" id="numero-serie-error">Le champ numéro de série est obligatoire.</label>
Attention, bien qu’il soit tout à fait HTML valide d’utiliser plusieurs label
pour un même champ de formulaire, il est pour le moment conseillé de doubler avec un attribut aria-labelledby
listant les id
des deux (ou plus) label
pour que le support soit assuré pour toutes les AT.
Consulter l’article de Steve Faulkner pour plus d’information sur le sujet.
<label id="serie-label" for="numero-serie">Veuillez saisir le numéro de série *</label>
<input aria-invalid="true" class="error" aria-labelledby="serie-label serie-error" id="numero-serie" aria-describedby="helpblock" aria-required="true" type="text">
<label id="serie-error" for="numero-serie" class="error" id="numero-serie-error">Le champ numéro de série est obligatoire.</label>
Afficher des messages d’erreur explicites et, si besoin, suggérer des corrections
Les messages d’erreur affichés doivent être pertinents et, si besoin, proposer des exemples d’entrée valide dits aussi suggestions de correction.
Pour les messages d'erreur, quelques règles de bases :
- Soyez clair et non ambigu
- Soyez bref et significatif
- Soyez précis et pertinent
- Donner des pistes de corrections et moyens de corriger
- Assurez-vous que les erreurs sont sous forme de texte, éviter les majuscules.
- Ne vous contentez pas d'utiliser des indicateurs visuels ou seulement la couleur pour signaler les erreurs.
- Laisser actif en toute circonstance le bouton d'envoi. Certains sites Web activent le bouton d'envoi que si le formulaire est correctement rempli, c'est une mauvaise idée.
- Fournissez les instructions nécessaires et soyez aussi précis que possible sur les erreurs commises afin de faciliter remplissage des champs par les utilisateurs.
- Assurez-vous que les erreurs sont visuellement identifiables sur la page Web.
Exemple valide :
Exemple non-valide :