Peels

Formulaires

Vue d'ensemble #

Conteneur de formulaire et champs labelisés

Informations personnelles
Message
<form>
  <fieldset>
    <legend>Informations personnelles</legend>

    <label for="form-nom">
      Nom
      <input type="text" id="form-nom" placeholder="Votre nom" autocomplete="name">
    </label>

    <label for="form-email">
      E-mail
      <small data-hint>Nous ne partagerons jamais votre e-mail.</small>
      <input type="email" id="form-email" placeholder="vous@exemple.fr" autocomplete="email">
    </label>
  </fieldset>

  <fieldset>
    <legend>Message</legend>

    <label for="form-message">
      Votre message
      <textarea id="form-message" placeholder="Votre message…" rows="4"></textarea>
    </label>
  </fieldset>

  <div data-layout="cluster">
    <button type="submit">Envoyer</button>
    <button type="reset">Réinitialiser</button>
  </div>
</form>

Champ de saisie #

Champs de saisie — input[type="text|email|tel|search|number|password"], textarea

<label for="input-text">
  Texte
  <input type="text" id="input-text" placeholder="Votre nom">
</label>
<label for="input-email">
  Adresse e-mail
  <input type="email" id="input-email" placeholder="vous@exemple.fr">
</label>
<label for="input-password">
  Mot de passe
  <input type="password" id="input-password" placeholder="••••••••">
</label>
<label for="input-search">
  Recherche
  <input type="search" id="input-search" placeholder="Chercher…">
</label>
<label for="input-number">
  Nombre
  <input type="number" id="input-number" placeholder="42">
</label>
<label for="input-required">
  Nom <em data-required aria-hidden="true">*</em>
  <input type="text" id="input-required" required placeholder="Votre nom">
</label>
<label for="input-readonly">
  Identifiant
  <input type="text" id="input-readonly" value="USR-4829" readonly>
</label>
<label for="input-disabled">
  Désactivé
  <input type="text" id="input-disabled" value="Non modifiable" disabled>
</label>
<label for="input-error" data-state="error">
  E-mail
  <small data-hint>Format attendu : nom@domaine.fr</small>
  <input type="email" id="input-error" value="invalide" aria-invalid="true" placeholder="vous@exemple.fr">
  <small data-error>L'adresse e-mail n'est pas valide.</small>
</label>
<label for="input-file">
  Avatar
  <input type="file" id="input-file" accept="image/*">
</label>
<label for="textarea">
  Message
  <textarea id="textarea" placeholder="Votre message…" rows="4"></textarea>
</label>
Date et heure
<fieldset>
  <legend>Date et heure</legend>

  <label for="input-date">
    Date
    <input type="date" id="input-date" value="2026-09-22">
  </label>

  <label for="input-month">
    Mois
    <input type="month" id="input-month" value="2026-09">
  </label>

  <label for="input-week">
    Semaine
    <input type="week" id="input-week" value="2026-W39">
  </label>

  <label for="input-time">
    Heure
    <input type="time" id="input-time" value="09:30">
  </label>

  <label for="input-datetime-local">
    Date et heure
    <input type="datetime-local" id="input-datetime-local" value="2026-09-22T09:30">
  </label>
</fieldset>
<label for="input-range">
  Volume
  <input type="range" id="input-range" min="0" max="100" value="60">
</label>

Case à cocher et radio #

Cases à cocher et boutons radio — input[type="checkbox"], input[type="radio"]

Checkbox
<fieldset>
  <legend>Checkbox</legend>
  <label><input type="checkbox" name="cb-demo" value="a"> Option A</label>
  <label><input type="checkbox" name="cb-demo" value="b" checked> Option B</label>
  <label><input type="checkbox" name="cb-demo" value="c"> Option C</label>
</fieldset>
Radio
<fieldset>
  <legend>Radio</legend>
  <label><input type="radio" name="radio-demo" value="1"> Choix 1</label>
  <label><input type="radio" name="radio-demo" value="2" checked> Choix 2</label>
  <label><input type="radio" name="radio-demo" value="3"> Choix 3</label>
</fieldset>
États
<fieldset>
  <legend>États</legend>
  <label><input type="checkbox" name="cb-states" value="req" required> Requise (validation native)</label>
  <label><input type="checkbox" name="cb-states" value="dis" disabled> Désactivée</label>
  <label><input type="checkbox" name="cb-states" value="dis-on" checked disabled> Cochée désactivée</label>
  <label><input type="checkbox" name="cb-states" value="inv" aria-invalid="true"> Invalide (aria-invalid)</label>
</fieldset>
Libellés riches
<fieldset>
  <legend>Libellés riches</legend>
  <label><input type="checkbox" name="cb-rich" value="terms"><span>J'accepte les <a href="#">conditions d'utilisation</a> et la politique de confidentialité du service.</span></label>
  <label><input type="checkbox" name="cb-rich" value="long"> Un libellé volontairement long pour vérifier que le texte se replie correctement sous lui-même sans repasser sous la case à cocher ni provoquer de débordement horizontal du conteneur.</label>
</fieldset>
Groupe horizontal (composition côté intégrateur)
<fieldset>
  <legend>Groupe horizontal (composition côté intégrateur)</legend>
  <div style="display: flex; flex-wrap: wrap; gap: var(--peels-gap-component);">
    <label><input type="radio" name="radio-inline" value="a" checked> Jour</label>
    <label><input type="radio" name="radio-inline" value="b"> Semaine</label>
    <label><input type="radio" name="radio-inline" value="c"> Mois</label>
  </div>
</fieldset>
Sélection multiple de messages (indeterminate)
Objet Expéditeur
Facture de septembre Comptabilité
Réunion d'équipe Direction
Lettre d'information Association
<fieldset>
  <legend>Sélection multiple de messages (indeterminate)</legend>
  <table>
    <thead>
      <tr>
        <th scope="col"><input type="checkbox" id="cb-all" aria-label="Sélectionner tous les messages"></th>
        <th scope="col">Objet</th>
        <th scope="col">Expéditeur</th>
      </tr>
    </thead>
    <tbody>
      <tr>
        <td><input type="checkbox" name="messages" value="invoice" aria-labelledby="message-invoice-subject message-invoice-sender" checked></td>
        <th scope="row" id="message-invoice-subject">Facture de septembre</th>
        <td id="message-invoice-sender">Comptabilité</td>
      </tr>
      <tr>
        <td><input type="checkbox" name="messages" value="meeting" aria-labelledby="message-meeting-subject message-meeting-sender"></td>
        <th scope="row" id="message-meeting-subject">Réunion d'équipe</th>
        <td id="message-meeting-sender">Direction</td>
      </tr>
      <tr>
        <td><input type="checkbox" name="messages" value="newsletter" aria-labelledby="message-newsletter-subject message-newsletter-sender"></td>
        <th scope="row" id="message-newsletter-subject">Lettre d'information</th>
        <td id="message-newsletter-sender">Association</td>
      </tr>
    </tbody>
  </table>
</fieldset>

Liste déroulante #

Menu déroulant natif — select, option, optgroup

Sélection simple et groupée
<fieldset>
  <legend>Sélection simple et groupée</legend>

  <label for="select-simple">
    Pays
    <select id="select-simple" name="country">
      <option value="">Choisir un pays…</option>
      <option value="fr">France</option>
      <option value="be">Belgique</option>
      <option value="ch">Suisse</option>
    </select>
  </label>

  <label for="select-groups">
    Thème
    <select id="select-groups" name="theme">
      <optgroup label="Clair">
        <option value="light-default">Défaut</option>
        <option value="light-warm">Chaud</option>
      </optgroup>
      <optgroup label="Sombre">
        <option value="dark-default">Défaut</option>
        <option value="dark-cool">Froid</option>
      </optgroup>
    </select>
  </label>
</fieldset>
États
<fieldset>
  <legend>États</legend>

  <label for="select-required">
    Service <em data-required aria-hidden="true">*</em>
    <select id="select-required" name="service" required>
      <option value="">Choisir…</option>
      <option value="support">Support</option>
      <option value="sales">Commercial</option>
      <option value="tech">Technique</option>
    </select>
  </label>

  <label for="select-disabled">
    Statut
    <select id="select-disabled" name="status" disabled>
      <option>En attente</option>
    </select>
  </label>

  <label for="select-invalid">
    Catégorie
    <select id="select-invalid" name="category" aria-invalid="true">
      <option value="">Sélection invalide…</option>
      <option value="a">Catégorie A</option>
      <option value="b">Catégorie B</option>
    </select>
  </label>
</fieldset>
Sélection multiple
<fieldset>
  <legend>Sélection multiple</legend>

  <label for="select-multiple">
    Compétences
    <select id="select-multiple" name="skills" multiple size="4">
      <option value="html">HTML</option>
      <option value="css" selected>CSS</option>
      <option value="js">JavaScript</option>
      <option value="a11y" selected>Accessibilité</option>
    </select>
  </label>
</fieldset>

Interrupteur #

Interrupteur d'activation immédiate — input[type="checkbox"][role="switch"]

Préférences
<fieldset>
  <legend>Préférences</legend>
  <label><input type="checkbox" role="switch" name="sw-prefs" value="notif"> Notifications activées</label>
  <label><input type="checkbox" role="switch" name="sw-prefs" value="dark" checked> Mode sombre automatique</label>
</fieldset>
États
<fieldset>
  <legend>États</legend>
  <label><input type="checkbox" role="switch" name="sw-states" value="off-dis" disabled> Option désactivée (arrêt)</label>
  <label><input type="checkbox" role="switch" name="sw-states" value="on-dis" checked disabled> Option verrouillée (marche)</label>
</fieldset>

Groupe de champs #

Groupe de champs de formulaire — fieldset, legend, small[data-hint]

Informations personnelles
<fieldset>
  <legend>Informations personnelles</legend>

  <label for="fs-nom">
    Nom
    <small data-hint>Utilisé uniquement pour l’affichage.</small>
    <input type="text" id="fs-nom" placeholder="Votre nom">
  </label>

  <label for="fs-email">
    E-mail
    <input type="email" id="fs-email" placeholder="vous@exemple.fr">
  </label>
</fieldset>

Progression #

Barre de progression — progress

Progression déterminée
<fieldset>
  <legend>Progression déterminée</legend>

  <label for="progress-active">
    Téléchargement (75 %)
    <progress id="progress-active" value="75" max="100">75 %</progress>
  </label>

  <label for="progress-complete">
    Installation terminée (100 %)
    <progress id="progress-complete" value="100" max="100">100 %</progress>
  </label>
</fieldset>
Progression indéterminée
<fieldset>
  <legend>Progression indéterminée</legend>

  <label for="progress-indeterminate">
    Synchronisation en cours…
    <progress id="progress-indeterminate">En cours</progress>
  </label>
</fieldset>

Jauge de mesure #

Jauge de mesure dans une plage connue — meter

Occupation du stockage
<fieldset>
  <legend>Occupation du stockage</legend>

  <label for="meter-storage">
    Espace utilisé (6,4 Go sur 10 Go)
    <meter id="meter-storage" min="0" max="10" value="6.4">6,4 Go sur 10 Go</meter>
  </label>
</fieldset>

Aide à la saisie #

Indicateur de champ requis, texte d'aide et message d'erreur — em[data-required], small[data-hint], small[data-error]

Notes intégrées au label (compact)
<fieldset>
  <legend>Notes intégrées au label (compact)</legend>

  <label for="fn-password">
    Mot de passe <em data-required aria-hidden="true">*</em>
    <small data-hint>Au moins 8 caractères, dont un chiffre.</small>
    <input type="password" id="fn-password" required minlength="8" pattern=".*[0-9].*">
    <small data-error>Saisissez au moins 8 caractères incluant un chiffre.</small>
  </label>

  <label for="fn-email" data-state="error">
    Adresse e-mail
    <small data-hint>Format attendu : nom@domaine.fr</small>
    <input type="email" id="fn-email" value="invalide" aria-invalid="true">
    <small data-error>L'adresse e-mail n'est pas valide.</small>
  </label>
</fieldset>
Notes dissociées via aria-describedby Lettres minuscules et tirets uniquement. Utilisez uniquement des lettres minuscules (a–z) et des tirets (-). Format attendu : https://exemple.fr Le domaine doit commencer par https://.
<fieldset>
  <legend>Notes dissociées via aria-describedby</legend>

  <label for="fn-user">Identifiant <em data-required aria-hidden="true">*</em></label>
  <small id="fn-user-hint" data-hint>Lettres minuscules et tirets uniquement.</small>
  <input type="text" id="fn-user" required pattern="[a-z\-]+" aria-describedby="fn-user-hint fn-user-error">
  <small id="fn-user-error" data-error>Utilisez uniquement des lettres minuscules (a–z) et des tirets (-).</small>

  <label for="fn-domain">Domaine</label>
  <small id="fn-domain-hint" data-hint>Format attendu : https://exemple.fr</small>
  <input type="url" id="fn-domain" value="http://" aria-invalid="true" aria-describedby="fn-domain-hint fn-domain-error">
  <small id="fn-domain-error" data-error>Le domaine doit commencer par https://.</small>
</fieldset>