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 :
.input-text, .input-checkbox, .input-radio, .textarea ou .menu-select.
Il faut lui ajouter la classe .js-mandatory pour en activer la vérification javascript.
Un paragraphe .infos.error pour le message erreur.

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

Pour les input de type date, on ajoute un attribut placeholder="aaaa-mm-jj" visible uniquement par les navigateurs qui n'affichent pas de calendrier (Safari et IE<=11) :
<div class="input-text input-date">
    <label for="date-m">date</label>
    <input type="date" name="date-m" id="date-m" class="js-mandatory" placeholder="aaaa-mm-jj">
    <p class="infos error" data-text="Vous devez saisir une date (aaaa-mm-jj)"></p>
</div>


input checkbox  :
<div class="input-check input-mandatory">
    <input type="checkbox" name="mandatory-checkbox" id="mandatory-checkbox" class="js-mandatory">
    <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 .input-mandatory au conteneur.
Afin d'assurer une navigation par clavier (touche tab), il faut ajouter l'attribut tabindex="0" aux labels.

input radio :
<div class="input-radio input-mandatory">
    <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 input-mandatory au conteneur, pas de .js-madatory 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="menu-select">
    <label for="select3">Mandatory select</label>
    <select id="select3" name="select3" class="js-mandatory">
        <optgroup label="optgroup label">
            <option value="#">Mandatory select</option>
            <option value="option1">Option 1</option>
            <option value="option2">Option 2</option>
        </optgroup>
    </select>
    <p class="infos error" data-text="Vous devez choisir une option"></p>
</div>

J'utilise un petit constructeur vanilla (vanilla-js-dropdown.js) qui "transforme" le menu select original en liste facile à habiller en CSS. Ce script gère aussi la balise <optgroup>.

.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.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

Le code javascript Vanilla applique un onblur à tous ces champs (ou équivalent selon le type).
Si le champs n'est pas valide (vide pour les input-text, email 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), 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

Tous les fichiers
forms.js
_forms.scss

Exemple

Input-radio

Titre radio-buttons

Input-radio Mandatory

Titre radio-buttons

Input-text

Mandatory input-text

Menu select

Default value = "#" pour tests javascript.

Input-check
Input-check mandatory
Text-area
Mandatory text-area