Formulaire avec vérification des saisies

HTML

Structure HTML particulière à respecter pour la mise en forme et la vérification javascript :
Le champs doit être placé dans un conteneur correspondant à son type.
Nouveauté 2022 : je me suis basé sur le code généré par les webforms Drupal :
.form-type-textfield, .form-type-checkbox, .js-form-type-radios, .form-type-textarea ou .form-type-select.

Pour activer la vérification javascript, il faut ajouter la classe .required aux inputs + un paragraphe .infos.error pour le message erreur.

Nouveauté 2022 : On peut facilement placer tous les labels DANS les inputs/select/textarea en rajoutant une classe .label-inside à un parent des input (la balise form par exemple).

input text/number/tel/email/date/password :
<div class="form-type-textfield">
    <label for="id">Label</label>
    <input type="TYPE" name="id" id="id" class="required">
    <p class="infos error" data-text="Texte erreur"></p>
</div>

Pour les input de type date, comme ils sont très particulier, ils nécessitent un traitement spécifique.
Il faut ajouter la classe .input-date au .form-type-textfield
et un attribut placeholder="aaaa-mm-jj" visible uniquement par les navigateurs qui n'affichent pas de calendrier (Safari et IE<=11) :
<div class="form-type-textfield input-date">
    <label for="date-m">date</label>
    <input type="date" name="date-m" id="date-m" class="required" placeholder="aaaa-mm-jj">
    <p class="infos error" data-text="Vous devez saisir une date (aaaa-mm-jj)"></p>
</div>


input checkbox  :
<div class="form-type-checkbox required">
    <input type="checkbox" name="mandatory-checkbox" id="mandatory-checkbox" class="required">
    <label tabindex="0" for="mandatory-checkbox">Mandatory</label>
    <p class="infos error" data-text="Vous devez cocher cette option"></p>
</div>

Il faut aussi ajouter la classe .required au conteneur.
Afin d'assurer une navigation par clavier (touche tab), il faut ajouter l'attribut tabindex="0" aux labels.

input radio :
<div class="js-form-type-radios required">
    <p class="legend">Titre radio-buttons</p>
    <input type="radio" name="choice" id="yes" value="yes">
    <label tabindex="0" for="yes">Oui</label>
    <input type="radio" name="choice" id="no" value="no">
    <label tabindex="0" for="no">Non</label>
    <p class="infos error" data-text="Vous devez faire un choix"></p>
</div>

Classe required au conteneur, pas de .required pour les inputs.
On peut ajouter un paragraphe .legend.
Afin d'assurer une navigation par clavier (touche tab), il faut ajouter l'attribut tabindex="0" aux labels.

select :
<div class="form-type-select">
    <label for="select3">Mandatory select</label>
    <select id="select3" name="select3" class="required">
        <option value="#">Mandatory select</option>
        <option value="option1">Option 1</option>
        <option value="option2">Option 2</option>
    </select>
    <p class="infos error" data-text="Vous devez choisir une option"></p>
</div>

Nouveauté 2022 :
Par défaut, les menus select sont rhabillés en javascript avec un petit constructeur vanilla (regalCustomSelect.js) qui "transforme" le menu select original en une liste facile à habiller en CSS. Ce script gère aussi la balise <optgroup>.
Pour ceux qui préfèrent garder le menu select visible (ça peut arriver !), il suffit de commenter quelques lignes de javascript (lignes #250 à #268).

.js-submit de la balise form :
<input type="submit" value="Submit" id="form-submit" class="js-submit">
<p class="submit-error" data-text="Veuillez vérifier votre saisie"></p>


Le submit doit être un enfant direct de la balise form et être suivi d'un paragraphe .submit-error pour afficher le message erreur.

Il faut ajouter un attribut novalidate à la balise form car la validation automatique n'est pas compatible avec la créa mise en place (les labels qui se déplacent au click). Tous les tests sont effectués en javascript.

reCaptcha

Tout d'abord, il faut s'inscrire sur google et créer ses clefs d'accès, siteKey et secretKey.
Je ne vais pas rentrer dans les détails de cette inscription, vous trouverez des informations précises ici.
Intégrer le javascript de Google à la page (tout en bas).
<script src="https://www.google.com/recaptcha/api.js?onload=renderRecaptcha&render=explicit" async defer></script>
renderRecaptcha est la fonction qui sera exécutée au chargement de ce js, elle est présente dans form.js. Elle initialise le captcha :
var renderRecaptcha = function () {
    grecaptcha.render('recaptcha-container', { //recaptcha-container est l'id du conteneur qui va afficher le reCaptcha
        'sitekey': yourSiteKey,
        'callback': reCaptchaCallback,
        theme: 'light', //light or dark
        //type: 'image',// image or audio
        size: 'normal'//normal or compact
    });
};

var reCaptchaCallback = function (response) {
    if (response !== '') {
        var elt = document.querySelector('.form-line.captcha');
        elt.classList.remove('error');
        var errorP = elt.querySelector('.error');
        if(errorP){
            errorP.classList.remove('error');
            errorP.innerHTML = '';
        }
    }
};


Le code HTML pour le reCaptcha est le suivant :
<fieldset class="form-line captcha">
    <div id="recaptcha-container"></div>
    <p class="infos error" data-text="Please check the box"></p>
</fieldset>


et form.js s'occupe de tout !

CSS / SCSS

Tous les styles sont regroupés dans un même fichier /scss/common/_form-v2.scss.
Les champs par défaut sont stylés au début du fichier.
Les conteneurs spécifiques en fin du fichier.
Selon les contextes, on pourra appliquer des styles différents à ces derniers (hauteur, largeur, polices, etc.).

Javascript

Fichier /javascripts/forms-v2.js.
Il applique un onblur à tous les champs mandatory (ou équivalent selon le type).
Si le champs n'est pas valide (vide pour les form-type-textfield, email non-valide pour les type=email, date au format aaaa-mm-jj pour les type=date, chiffre pour les type=number, aucun input:checked pour radio et checkbox, value vide pour select), on ajoute la classe .error à son conteneur et la valeur de l'attribut data-text du paragraphe .error est écrite dans ce même paragraphe.

Ce processus est également effectué au click sur le bouton .js-submit
Lorsqu'une erreur de saisie est détectée, le bouton submit passe en rouge (classe .error) et un message erreur est affiché dessous, dans un paragraphe .submit-error (le texte à afficher est écrit dans l'attribut data-text du paragraphe).
La classe .error est enlevée au bouton après 2 secondes

Télécharger

forms-v2.js
regalCustomSelect.js
_forms-v2.scss

Exemple en live

Input-text: classe .form-type-textfield

Mandatory .form-type-textfield

Menu select .form-type-select

Default value = "" pour tests javascript.

Message de succès

Informations

Informations

.form-type-checkbox
.form-type-checkbox mandatory

Input-radio .js-form-type-radios

Titre radio-buttons

Mandatory .js-form-type-radios

Titre radio-buttons

.form-type-textarea
Mandatory .form-type-textarea