Tableaux et formulaires en HTML 5

Sommaire

Un tableau HTML sert à présenter des données tabulaires : des valeurs qui se lisent en croisant lignes et colonnes. Historiquement, les tableaux ont aussi été détournés pour faire de la mise en page ; cette pratique est aujourd’hui à proscrire absolument — c’est le rôle de CSS (Flexbox et Grid, chapitre 8).

4.1. Tableau simple

Un tableau est délimité par <table>. Chaque ligne est un <tr> (table row), qui contient des cellules de deux types : <th> (table header) pour les en-têtes et <td> (table data) pour les données. Une légende, fortement recommandée, s’ajoute avec <caption> en premier enfant de <table>.

Sur chaque <th>, l’attribut scope= précise la portée de l’en-tête : col (la colonne entière) ou row (la ligne entière).

<table>
    <caption>Heures de travail nécessaires à la production d'une unité</caption>
    <tr>
        <th scope="col">Pays</th>
        <th scope="col">Drap</th>
        <th scope="col">Vin</th>
    </tr>
    <tr>
        <th scope="row">Angleterre</th>
        <td>100</td>
        <td>120</td>
    </tr>
    <tr>
        <th scope="row">Portugal</th>
        <td>90</td>
        <td>80</td>
    </tr>
</table>

4.2. En-tête, corps et pied de tableau

Comme la page elle-même, un tableau peut être structuré en trois zones : <thead> (lignes d’en-tête), <tbody> (corps) et <tfoot> (ligne de synthèse : totaux, moyennes…). Cette structure clarifie le code et permet, en CSS, de styler chaque zone séparément.

<table>
    <caption>Fréquentation mensuelle</caption>
    <thead>
        <tr>
            <th scope="col">Mois</th>
            <th scope="col">Visiteurs</th>
        </tr>
    </thead>
    <tbody>
        <tr>
            <th scope="row">Janvier</th>
            <td>1 240</td>
        </tr>
        <tr>
            <th scope="row">Février</th>
            <td>1 105</td>
        </tr>
    </tbody>
    <tfoot>
        <tr>
            <th scope="row">Total</th>
            <td>2 345</td>
        </tr>
    </tfoot>
</table>

4.3. Tableaux complexes

Un tableau est dit complexe dès qu’une cellule s’étend sur plusieurs lignes ou colonnes, au moyen des attributs rowspan= et colspan=.

Ces fusions perturbent la lecture automatique : le simple scope= ne suffit plus à relier chaque donnée à ses en-têtes. La solution : donner un identifiant (id=) à chaque <th>, puis lister explicitement dans chaque <td> les identifiants de ses en-têtes via l’attribut headers=.

<table>
    <caption>Chiffre d'affaires semestriel</caption>
    <thead>
        <tr>
            <th id="entreprise" rowspan="2">Entreprise</th>
            <th id="ca" colspan="2">Chiffre d'affaires</th>
        </tr>
        <tr>
            <th id="semestre-1" headers="ca">1er semestre</th>
            <th id="semestre-2" headers="ca">2e semestre</th>
        </tr>
    </thead>
    <tbody>
        <tr>
            <th id="societe-1" headers="entreprise">Société 1</th>
            <td headers="societe-1 semestre-1">10</td>
            <td headers="societe-1 semestre-2">20</td>
        </tr>
        <tr>
            <th id="societe-2" headers="entreprise">Société 2</th>
            <td headers="societe-2 semestre-1">30</td>
            <td headers="societe-2 semestre-2">40</td>
        </tr>
    </tbody>
    <tfoot>
        <tr>
            <th id="total" headers="entreprise">Total</th>
            <td headers="total semestre-1">40</td>
            <td headers="total semestre-2">60</td>
        </tr>
    </tfoot>
</table>

Un formulaire permet à l’utilisateur de saisir des données et de les envoyer au serveur. Il est délimité par la balise de type bloc <form> et contient des contrôles : champs de saisie, listes, cases à cocher, boutons…

5.1. Le contrôle universel : <input>

La plupart des contrôles se déclarent avec la balise vide <input>. Deux attributs sont essentiels : name=, le nom sous lequel la donnée sera transmise au serveur, et type=, qui détermine la nature du contrôle :

TypeDescription
textChamp de texte libre sur une ligne
numberValeur numérique (avec attributs min=, max=, step=)
emailAdresse électronique (validation automatique du format)
telNuméro de téléphone (affiche le clavier numérique sur mobile)
urlAdresse web (validation automatique du format)
passwordMot de passe (saisie masquée)
checkboxCase à cocher (choix multiples)
radioBouton radio (choix unique parmi les input partageant le même name=)
date / timeSélecteur de date / d’heure
colorSélecteur de couleur
fileSélecteur de fichier à téléverser
hiddenValeur transmise sans être affichée

L’attribut value= fixe une valeur initiale. Pour les cases à cocher et boutons radio, l’attribut checked présélectionne le contrôle.

5.2. Listes déroulantes : <select>

Une liste déroulante se construit avec <select> (qui porte le name=) et des <option> :

<label for="visite">Visite guidée souhaitée</label>
<select name="visite" id="visite">
    <option value="">— Choisir une visite —</option>
    <option value="vieux-port">Le vieux port</option>
    <option value="citadelle" selected>La citadelle</option>
</select>

L’attribut selected présélectionne une option ; <optgroup label="…"> permet de regrouper des options sous un intitulé commun.

5.3. Zones de texte multilignes : <textarea>

Pour une saisie libre sur plusieurs lignes, <textarea> s’utilise avec une balise ouvrante et une balise fermante. rows= et cols= suggèrent ses dimensions initiales, maxlength= limite la longueur du texte.

5.4. Boutons

Un bouton se définit avec <button>, dont le nœud texte constitue le libellé. Son attribut type= prend trois valeurs :

  • submit (valeur par défaut) : déclenche l’envoi du formulaire ;
  • reset : réinitialise tous les contrôles à leur valeur initiale (à utiliser avec prudence : un clic malheureux efface toute la saisie) ;
  • button : sans effet propre, pour un comportement défini en JavaScript.

5.5. Libellés et regroupements : la clé de l’accessibilité

Chaque contrôle doit avoir un libellé, déclaré avec <label>. Deux écritures sont possibles :

<!-- Liaison explicite par for/id (recommandée) -->
<label for="courriel">Adresse électronique</label>
<input type="email" name="courriel" id="courriel">
 
<!-- Liaison par imbrication -->
<label>
    Adresse électronique
    <input type="email" name="courriel">
</label>

Les contrôles apparentés — typiquement une série de boutons radio — se regroupent dans un <fieldset>, dont le premier enfant <legend> donne l’intitulé du groupe :

<fieldset>
    <legend>Formule d'abonnement</legend>
    <label><input type="radio" name="formule" value="simple" checked> Simple</label>
    <label><input type="radio" name="formule" value="famille"> Famille</label>
</fieldset>

5.6. Validation et envoi des données

L’attribut required, ajouté à un contrôle, le rend obligatoire : le navigateur bloque l’envoi et signale le champ s’il est vide. Les attributs min=, max=, maxlength= et pattern= (expression régulière) complètent cette validation native, qui reste une aide à la saisie : le serveur doit toujours revalider les données.

L’envoi est piloté par deux attributs de <form> :

  • action= : URL destinataire des données (facultatif si c’est la page courante) ;
  • method= : get transmet les valeurs dans l’URL (?nom=valeur&autre=valeur), adapté aux recherches et filtres ; post les transmet dans le corps de la requête HTTP, obligatoire dès que les données sont sensibles ou modifient un état côté serveur.
<form action="/inscription" method="post">
    <label for="nom">Nom</label>
    <input type="text" name="nom" id="nom" autocomplete="family-name" required>
 
    <label for="courriel">Adresse électronique</label>
    <input type="email" name="courriel" id="courriel" autocomplete="email" required>
 
    <button type="submit">S'inscrire</button>
</form>