Aller au contenu
← 1001 Widgets
N° 019 · ●●○

Formulaire qui se valide

Un formulaire qui explique ses erreurs champ par champ, au bon moment et avec des mots simples. Le bon exercice pour valider sans agacer la personne qui écrit.

HTMLJS
Ce qu'on apprend
  • Valider au départ du champ, pas à chaque touche
  • Relier un message d'erreur avec aria-describedby
  • Placer le focus sur la première erreur
Pourquoi ce langage

Pourquoi un formulaire qui se valide ? Un formulaire mal fait fait fuir. Le pire : tout effacer après une erreur, ou crier « invalide » dès la première lettre tapée.

La bonne recette : on vérifie un champ quand on le quitte, puis en direct une fois qu'il a été touché. Au moment d'envoyer, on vérifie tout et on emmène le curseur vers la première erreur.

Pourquoi en JavaScript simple ? Un objet de règles, une fonction de vérification, trois écouteurs. C'est le cœur de toutes les bibliothèques de formulaires.

Comment ça marche
  1. LE HTML

    novalidate coupe les bulles du navigateur, pour afficher nos propres messages.

    <form id="f" novalidate>
      <label for="mail">E-mail</label>
      <input id="mail" type="email" aria-describedby="e-mail">
      <span id="e-mail" aria-live="polite"></span>
      <button>Envoyer</button>
    </form>
  2. LES RÈGLES

    Chaque règle renvoie un message, ou une chaîne vide si tout va bien.

    const REGLES = {
      mail: v => !v.trim() ? "L'e-mail est obligatoire."
        : !/^[^\s@]+@[^\s@]+\.[^\s@]{2,}$/.test(v.trim()) ? 'Il manque peut-être le domaine.' : ''
    };
  3. VÉRIFIER UN CHAMP

    function verifier(id) {
      const champ = document.getElementById(id);
      const message = REGLES[id](champ.value);
      champ.setAttribute('aria-invalid', String(Boolean(message)));
      document.getElementById('e-' + id).textContent = message;
      return !message;
    }
  4. LE BON MOMENT

    Au départ du champ d'abord, puis en direct une fois qu'il a été touché.

    const touche = {};
    for (const id in REGLES) {
      const champ = document.getElementById(id);
      champ.addEventListener('blur', () => { touche[id] = true; verifier(id); });
      champ.addEventListener('input', () => { if (touche[id]) verifier(id); });
    }
  5. ENVOYER

    On vérifie tout, et on emmène le focus sur la première erreur.

    document.getElementById('f').addEventListener('submit', e => {
      e.preventDefault();
      const erreurs = Object.keys(REGLES).filter(id => !verifier(id));
      if (erreurs.length) return document.getElementById(erreurs[0]).focus();
      // ici : envoyer au serveur
    });
Pièges

PIÈGE 1 : Crier trop tôt

Piège

Mauvais : afficher « e-mail invalide » dès la première lettre. On n'a même pas fini d'écrire.

Fix

Correct : vérifier au blur, puis en direct seulement une fois le champ touché.

PIÈGE 2 : Un message que personne n'entend

Piège

Mauvais : un texte rouge posé à côté du champ. Un lecteur d'écran ne sait pas qu'il existe.

Fix

Correct : aria-describedby sur le champ, aria-invalid quand il y a une erreur, aria-live sur le message.

PIÈGE 3 : Croire que c'est sécurisé

Piège

Mauvais : ne valider que dans le navigateur. N'importe qui peut envoyer une requête sans passer par la page.

Fix

Correct : refaire les mêmes vérifications côté serveur. Le JavaScript sert au confort, pas à la sécurité.

PERSONNALISER
  • Un compteur de caractères sous le message, qui rappelle le minimum.
  • Une suggestion pour les fautes courantes : « gmial.com », vouliez-vous dire « gmail.com » ?
  • Un bouton qui affiche « Envoi… » et se désactive pendant la requête.
OPTIMISATION
  • Partagez le même objet de règles entre le navigateur et le serveur pour n'écrire chaque règle qu'une fois.
  • Gardez les champs remplis après une erreur serveur : ne jamais faire retaper un message.
VERS REACT

Les valeurs, les erreurs et les champs touchés vivent dans un useState chacun, ou un useReducer.

Les règles restent un objet en dehors du composant.

Pour un gros formulaire, une bibliothèque comme React Hook Form reprend exactement cette logique.

Variantes
Commentaires
0/1000

Chargement des commentaires…