Skip to content
← 1001 Widgets
N° 019 · ●●○

Self-validating form

A form that explains its errors field by field, at the right moment and in plain words. The right exercise to validate without annoying the person typing.

HTMLJS
What you'll learn
  • Validate when leaving a field, not on every key
  • Link an error message with aria-describedby
  • Move focus to the first error
Why this language

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.

How it works
  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
    });
Pitfalls

PIÈGE 1 : Crier trop tôt

Pitfall

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

Pitfall

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é

Pitfall

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.

Variants
Comments
0/1000

Loading comments…

Audience measurement

With your consent, this site measures its traffic with Google Analytics and the Meta pixel, via Google Tag Manager. Nothing is loaded until you choose, and you can change your mind at any time with the "Cookies" link at the bottom of the page.