Certains champs de formulaire ne se comprennent qu’en groupe. Un bouton radio “Oui” sans contexte ne veut rien dire. “Oui” à quelle question ? Une case à cocher “Lundi” sans contexte ne précise pas ce qu’on accepte pour le lundi. Le <fieldset> et la <legend> existent pour fournir ce contexte.
Le problème que fieldset résout
Quand un utilisateur de lecteur d’écran navigue dans un formulaire champ par champ, il entend chaque élément isolément. Sans regroupement, des boutons radio “Matin”, “Après-midi”, “Soirée” sont annoncés sans lien entre eux :
→ NVDA : "Matin, bouton radio, non sélectionné, 1 sur 3"
→ NVDA : "Après-midi, bouton radio, non sélectionné, 2 sur 3"
→ NVDA : "Soirée, bouton radio, non sélectionné, 3 sur 3"
Matin quoi ? Après-midi pour quelle préférence ? L’utilisateur doit naviguer en arrière pour trouver la question, puis revenir aux boutons.
Avec un <fieldset> et une <legend> :
<fieldset>
<legend>Créneau préféré pour votre rendez-vous</legend>
<label><input type="radio" name="creneau" value="matin"> Matin</label>
<label><input type="radio" name="creneau" value="apres-midi"> Après-midi</label>
<label><input type="radio" name="creneau" value="soiree"> Soirée</label>
</fieldset>
→ NVDA : "Créneau préféré pour votre rendez-vous, groupe"
→ NVDA : "Matin, bouton radio, non sélectionné, 1 sur 3"
→ NVDA : "Après-midi, bouton radio, non sélectionné, 2 sur 3"
La <legend> est annoncée à l’entrée du groupe et avant chaque bouton radio selon les paramètres NVDA. L’utilisateur comprend immédiatement le contexte.
Quand utiliser fieldset, la règle simple
Toujours utiliser <fieldset> + <legend> pour :
- Les groupes de boutons radio (plusieurs options, un seul choix)
- Les groupes de cases à cocher (plusieurs options, choix multiples possibles)
- Les adresses postales (rue, code postal, ville, plusieurs champs pour une même information)
- Les dates de naissance (jour, mois, année, plusieurs champs pour une seule donnée)
- Tout groupe de champs qui ne se comprend qu’ensemble
Ne pas utiliser <fieldset> pour :
- Un seul champ avec son label, le
<label>suffit - L’ensemble d’un formulaire simple à moins que tous les champs forment un groupe thématique cohérent
- Créer une mise en page :
<fieldset>a une signification sémantique, pas une fonction de layout
Les boutons radio sont toujours dans un fieldset
C’est le cas le plus fréquent et le plus clair. Des boutons radio représentent un choix mutuellement exclusif parmi plusieurs options. Le <fieldset> fournit la question, chaque <label> fournit la réponse.
<!-- ✗ Sans fieldset — contexte manquant -->
<p>Quel est votre statut ?</p>
<label><input type="radio" name="statut" value="locataire"> Locataire</label>
<label><input type="radio" name="statut" value="proprietaire"> Propriétaire</label>
<label><input type="radio" name="statut" value="autre"> Autre</label>
<!-- ✓ Avec fieldset — contexte dans la légende -->
<fieldset>
<legend>Quel est votre statut ?</legend>
<label><input type="radio" name="statut" value="locataire"> Locataire</label>
<label><input type="radio" name="statut" value="proprietaire"> Propriétaire</label>
<label><input type="radio" name="statut" value="autre"> Autre</label>
</fieldset>
La <legend> reprend la question. Ce n’est pas un titre de section générique comme “Statut”, c’est la question complète que les options permettent de répondre.
Navigation clavier dans un groupe de boutons radio
Tab entre dans le groupe et se pose sur le bouton radio sélectionné (ou le premier si aucun n’est sélectionné). Les flèches gauche/droite ou haut/bas naviguent entre les options du groupe. Tab sort du groupe vers le champ suivant.
C’est le comportement natif sans besoin de JavaScript supplémentaire.
Les cases à cocher : fieldset quand elles forment un groupe
Contrairement aux boutons radio, les cases à cocher peuvent être cochées indépendamment. Mais quand elles forment un groupe thématique, le <fieldset> reste nécessaire.
<!-- ✗ Sans fieldset — "Lundi" est incompréhensible seul -->
<p>Jours disponibles</p>
<label><input type="checkbox" name="jours" value="lun"> Lundi</label>
<label><input type="checkbox" name="jours" value="mar"> Mardi</label>
<label><input type="checkbox" name="jours" value="mer"> Mercredi</label>
<!-- ✓ Avec fieldset -->
<fieldset>
<legend>Jours disponibles pour votre rendez-vous</legend>
<label><input type="checkbox" name="jours" value="lun"> Lundi</label>
<label><input type="checkbox" name="jours" value="mar"> Mardi</label>
<label><input type="checkbox" name="jours" value="mer"> Mercredi</label>
</fieldset>
Exception : une case à cocher unique avec un label explicite n’a pas besoin de fieldset.
<!-- ✓ Case à cocher unique, le label suffit -->
<label>
<input type="checkbox" name="newsletter" value="1">
Je souhaite recevoir la newsletter mensuelle de la commune
</label>
<!-- ✓ Aussi valide avec for/id -->
<input type="checkbox" id="cgu" name="cgu" value="1">
<label for="cgu">J'accepte les conditions générales d'utilisation</label>
Les adresses et données composées
Une adresse postale est une information unique, mais elle nécessite plusieurs champs. Sans regroupement, les champs “Rue”, “Code postal”, “Ville” semblent indépendants.
<fieldset>
<legend>Adresse postale</legend>
<label for="rue">Numéro et nom de rue</label>
<input type="text" id="rue" name="rue" autocomplete="street-address">
<label for="cp">Code postal</label>
<input type="text" id="cp" name="cp"
inputmode="numeric" autocomplete="postal-code">
<label for="ville">Ville</label>
<input type="text" id="ville" name="ville" autocomplete="address-level2">
</fieldset>
Même logique pour une date de naissance en trois champs :
<fieldset>
<legend>Date de naissance</legend>
<label for="naissance-jour">Jour</label>
<input type="number" id="naissance-jour" name="naissance-jour"
min="1" max="31" inputmode="numeric">
<label for="naissance-mois">Mois</label>
<input type="number" id="naissance-mois" name="naissance-mois"
min="1" max="12" inputmode="numeric">
<label for="naissance-annee">Année</label>
<input type="number" id="naissance-annee" name="naissance-annee"
min="1900" max="2026" inputmode="numeric">
</fieldset>
Ce que doit contenir la <legend>
La <legend> est annoncée avant chaque champ du groupe par certains lecteurs d’écran. Elle doit donc être :
Concise : une phrase courte, la question ou le thème du groupe. Une <legend> de trois paragraphes serait lue avant chaque bouton radio, ce qui serait épuisant pour l’utilisateur.
Informative : pas un label générique. “Vos informations”, “Section 1”, “Champs obligatoires” ne constituent pas des légendes pertinentes.
Complète : la <legend> est parfois lue séparément de son contexte. Elle doit se suffire à elle-même.
<!-- ✗ NC — légende trop vague -->
<fieldset>
<legend>Préférence</legend>
<label><input type="radio" name="mode" value="email"> Email</label>
<label><input type="radio" name="mode" value="tel"> Téléphone</label>
</fieldset>
<!-- ✓ C — légende complète -->
<fieldset>
<legend>Mode de contact préféré pour nos réponses</legend>
<label><input type="radio" name="mode" value="email"> Email</label>
<label><input type="radio" name="mode" value="tel"> Téléphone</label>
</fieldset>
Fieldsets imbriqués
Il est possible d’imbriquer des <fieldset> pour des formulaires complexes à plusieurs niveaux de regroupement.
<fieldset>
<legend>Disponibilités</legend>
<fieldset>
<legend>Semaine du 10 au 14 mars</legend>
<label><input type="checkbox" name="s1" value="lun"> Lundi</label>
<label><input type="checkbox" name="s1" value="mar"> Mardi</label>
</fieldset>
<fieldset>
<legend>Semaine du 17 au 21 mars</legend>
<label><input type="checkbox" name="s2" value="lun"> Lundi</label>
<label><input type="checkbox" name="s2" value="mar"> Mardi</label>
</fieldset>
</fieldset>
L’imbrication est valide en HTML et bien supportée par les AT. À utiliser avec parcimonie, car chaque niveau de groupe ajoute une annonce à la navigation.
Ce que le RGAA exige
Critère 11.5 : Dans chaque formulaire, les champs de même nature sont-ils regroupés, si nécessaire ?
Les champs qui forment un groupe thématique doivent être regroupés. “Si nécessaire” signifie : quand le label seul ne suffit pas à comprendre le contexte du champ. Les boutons radio et les cases à cocher en groupe nécessitent toujours un regroupement.
Critère 11.6 : Dans chaque formulaire, chaque regroupement de champs de même nature a-t-il une légende ?
Un <fieldset> sans <legend>, ou avec une <legend> vide, est une non-conformité. La légende est obligatoire et doit être pertinente, elle doit permettre de comprendre le contexte du groupe de champs.