Back

Gestion des Formulaires avec JavaScript Vanilla : Aucun Framework Requis

Gestion des Formulaires avec JavaScript Vanilla : Aucun Framework Requis

Les formulaires constituent l’épine dorsale de l’interaction utilisateur sur le web. Bien que les frameworks comme React et Vue offrent des abstractions pratiques, comprendre comment gérer les formulaires avec JavaScript vanilla vous donne un contrôle total et élimine les dépendances inutiles.

Ce guide vous accompagne à travers tout ce que vous devez savoir sur la gestion native des formulaires en JavaScript—de la sélection d’éléments et la capture de valeurs à la validation des entrées et au traitement des soumissions.

Points Clés à Retenir

  • JavaScript vanilla fournit tous les outils nécessaires pour une gestion complète des formulaires sans frameworks
  • Utilisez event.preventDefault() pour contrôler le comportement de soumission des formulaires
  • Tirez parti de la validation par contraintes HTML5 pour une validation de base avec un minimum de code
  • Implémentez une validation en temps réel avec les événements input et blur pour une meilleure expérience utilisateur
  • L’API FormData simplifie la collecte et le traitement des valeurs de formulaire
  • Considérez toujours l’accessibilité lors de l’implémentation de validation personnalisée de formulaires

Gestion de Base des Formulaires avec JavaScript

Commençons par un formulaire HTML simple :

<form id="signup-form">
  <div>
    <label for="username">Username:</label>
    <input type="text" id="username" name="username">
  </div>
  <div>
    <label for="email">Email:</label>
    <input type="email" id="email" name="email">
  </div>
  <div>
    <label for="password">Password:</label>
    <input type="password" id="password" name="password">
  </div>
  <button type="submit">Sign Up</button>
</form>

Sélection des Éléments de Formulaire

Vous pouvez accéder à un formulaire et à ses éléments de plusieurs façons :

// Sélection par ID (recommandé pour des formulaires spécifiques)
const form = document.getElementById('signup-form');

// Sélection avec querySelector
const form = document.querySelector('#signup-form');

// Accès à la collection des formulaires
const forms = document.forms;
const signupForm = forms['signup-form']; // par id/nom
const firstForm = forms[0]; // par index

Capture de l’Événement de Soumission

Pour traiter la soumission du formulaire, ajoutez un écouteur d’événement au formulaire :

const form = document.getElementById('signup-form');

form.addEventListener('submit', function(event) {
  // Empêcher la soumission par défaut du formulaire
  event.preventDefault();
  
  // Traiter les données du formulaire ici
  console.log('Formulaire soumis !');
});

La méthode preventDefault() empêche le navigateur de soumettre le formulaire et d’actualiser la page, vous donnant le contrôle sur ce qui se passe ensuite.

Accès aux Valeurs des Champs de Saisie

Il existe plusieurs façons d’accéder aux valeurs des champs de saisie :

Méthode 1 : Accès aux Éléments Individuels

form.addEventListener('submit', function(event) {
  event.preventDefault();
  
  // Obtenir les valeurs des éléments individuels du formulaire
  const username = document.getElementById('username').value;
  const email = document.getElementById('email').value;
  const password = document.getElementById('password').value;
  
  console.log(username, email, password);
});

Méthode 2 : Utilisation de form.elements

La propriété elements fournit l’accès à tous les contrôles du formulaire :

form.addEventListener('submit', function(event) {
  event.preventDefault();
  
  // Accès via la collection elements
  const username = form.elements.username.value;
  const email = form.elements.email.value;
  const password = form.elements.password.value;
  
  console.log(username, email, password);
});

Méthode 3 : Utilisation de l’API FormData

L’API FormData fournit une façon propre de capturer toutes les valeurs du formulaire :

form.addEventListener('submit', function(event) {
  event.preventDefault();
  
  // Créer un objet FormData à partir du formulaire
  const formData = new FormData(form);
  
  // Accéder aux valeurs individuelles
  const username = formData.get('username');
  const email = formData.get('email');
  
  // Convertir en objet ordinaire
  const formObject = Object.fromEntries(formData);
  console.log(formObject); // {username: '...', email: '...', password: '...'}
});

Validation de Formulaire avec les Contraintes HTML5

Le HTML5 moderne fournit des attributs de validation intégrés qui fonctionnent sans JavaScript :

<form id="signup-form">
  <div>
    <label for="username">Username:</label>
    <input type="text" id="username" name="username" required minlength="3">
  </div>
  <div>
    <label for="email">Email:</label>
    <input type="email" id="email" name="email" required>
  </div>
  <div>
    <label for="password">Password:</label>
    <input type="password" id="password" name="password" required minlength="8" 
           pattern="^(?=.*[a-z])(?=.*[A-Z])(?=.*\d).*$">
    <small>Le mot de passe doit contenir au moins 8 caractères, incluant majuscules, minuscules et chiffres</small>
  </div>
  <button type="submit">Sign Up</button>
</form>

Les attributs de validation courants incluent :

  • required : Le champ doit être rempli
  • minlength/maxlength : Longueur minimale/maximale du texte
  • min/max : Valeurs minimales/maximales pour les entrées numériques
  • pattern : Motif d’expression régulière à respecter
  • type="email" : Valide le format d’email
  • type="url" : Valide le format d’URL

Exploitation de l’API de Validation par Contraintes

JavaScript peut accéder au système de validation intégré du navigateur :

form.addEventListener('submit', function(event) {
  // Vérifier si le formulaire est valide en utilisant l'API de Validation par Contraintes
  if (!form.checkValidity()) {
    // Le formulaire est invalide - laisser le navigateur gérer l'affichage des erreurs
    return;
  }
  
  // Si nous arrivons ici, le formulaire est valide
  event.preventDefault();
  
  // Traiter les données valides du formulaire
  console.log('Le formulaire est valide, traitement des données...');
});

Vous pouvez également vérifier la validité d’entrées spécifiques :

const emailInput = document.getElementById('email');

// Vérifier si l'email est valide
if (emailInput.validity.valid) {
  console.log('L\'email est valide');
} else {
  // Vérifier les échecs de validation spécifiques
  if (emailInput.validity.typeMismatch) {
    console.log('Le format de l\'email est incorrect');
  }
  if (emailInput.validity.valueMissing) {
    console.log('L\'email est requis');
  }
}

Validation Personnalisée et Messages d’Erreur

Bien que la validation HTML5 soit pratique, vous avez souvent besoin de logique de validation personnalisée et de messages d’erreur :

form.addEventListener('submit', function(event) {
  event.preventDefault();
  
  const username = document.getElementById('username');
  const email = document.getElementById('email');
  const password = document.getElementById('password');
  
  // Effacer les messages d'erreur précédents
  clearErrors();
  
  let isValid = true;
  
  // Validation personnalisée du nom d'utilisateur
  if (username.value.trim() === '') {
    displayError(username, 'Le nom d\'utilisateur est requis');
    isValid = false;
  } else if (username.value.length < 3) {
    displayError(username, 'Le nom d\'utilisateur doit contenir au moins 3 caractères');
    isValid = false;
  }
  
  // Validation personnalisée de l'email
  if (!isValidEmail(email.value)) {
    displayError(email, 'Veuillez saisir une adresse email valide');
    isValid = false;
  }
  
  // Validation personnalisée du mot de passe
  if (password.value.length < 8) {
    displayError(password, 'Le mot de passe doit contenir au moins 8 caractères');
    isValid = false;
  } else if (!/[A-Z]/.test(password.value)) {
    displayError(password, 'Le mot de passe doit contenir au moins une lettre majuscule');
    isValid = false;
  }
  
  // Si valide, traiter le formulaire
  if (isValid) {
    console.log('Le formulaire est valide, soumission...');
    // Soumettre les données du formulaire
  }
});

function isValidEmail(email) {
  return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email);
}

function displayError(input, message) {
  const formControl = input.parentElement;
  const errorElement = document.createElement('div');
  errorElement.className = 'error-message';
  errorElement.textContent = message;
  formControl.appendChild(errorElement);
  input.classList.add('error-input');
}

function clearErrors() {
  document.querySelectorAll('.error-message').forEach(error => error.remove());
  document.querySelectorAll('.error-input').forEach(input => {
    input.classList.remove('error-input');
  });
}

Validation en Temps Réel avec les Événements Input

Pour une meilleure expérience utilisateur, validez les entrées pendant que les utilisateurs tapent :

const emailInput = document.getElementById('email');

emailInput.addEventListener('input', function() {
  if (this.value && !isValidEmail(this.value)) {
    this.setCustomValidity('Veuillez saisir une adresse email valide');
  } else {
    this.setCustomValidity('');
  }
});

function isValidEmail(email) {
  return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email);
}

L’événement input se déclenche chaque fois que l’utilisateur modifie la valeur, tandis que l’événement change se déclenche lorsque l’entrée perd le focus après avoir été modifiée.

Gestion des Différents Types d’Entrée

Boutons Radio

<div>
  <p>Plan d'abonnement :</p>
  <label>
    <input type="radio" name="plan" value="free" checked> Gratuit
  </label>
  <label>
    <input type="radio" name="plan" value="premium"> Premium
  </label>
</div>
// Obtenir la valeur du bouton radio sélectionné
const selectedPlan = document.querySelector('input[name="plan"]:checked').value;

// Écouter les changements
document.querySelectorAll('input[name="plan"]').forEach(radio => {
  radio.addEventListener('change', function() {
    console.log('Plan sélectionné :', this.value);
  });
});

Cases à Cocher

<div>
  <p>Centres d'intérêt :</p>
  <label>
    <input type="checkbox" name="interests" value="javascript"> JavaScript
  </label>
  <label>
    <input type="checkbox" name="interests" value="html"> HTML
  </label>
  <label>
    <input type="checkbox" name="interests" value="css"> CSS
  </label>
</div>
// Obtenir toutes les valeurs cochées
function getSelectedInterests() {
  const checkboxes = document.querySelectorAll('input[name="interests"]:checked');
  const values = Array.from(checkboxes).map(cb => cb.value);
  return values;
}

// Lors de la soumission du formulaire
form.addEventListener('submit', function(event) {
  event.preventDefault();
  const interests = getSelectedInterests();
  console.log('Centres d\'intérêt sélectionnés :', interests);
});

Listes Déroulantes Select

<div>
  <label for="country">Pays :</label>
  <select id="country" name="country">
    <option value="">Sélectionnez un pays</option>
    <option value="us">États-Unis</option>
    <option value="ca">Canada</option>
    <option value="uk">Royaume-Uni</option>
  </select>
</div>
// Obtenir la valeur sélectionnée
const country = document.getElementById('country').value;

// Écouter les changements
document.getElementById('country').addEventListener('change', function() {
  console.log('Pays sélectionné :', this.value);
});

Exemple Complet de Traitement de Formulaire

Rassemblons tout dans un exemple complet :

document.addEventListener('DOMContentLoaded', function() {
  const form = document.getElementById('signup-form');
  
  // Ajouter la validation en temps réel
  setupRealTimeValidation();
  
  form.addEventListener('submit', function(event) {
    event.preventDefault();
    
    if (validateForm()) {
      // Créer un objet avec les données du formulaire
      const formData = new FormData(form);
      const userData = Object.fromEntries(formData);
      
      // Ici vous enverriez typiquement les données à un serveur
      console.log('Soumission des données utilisateur :', userData);
      
      // Simuler un appel API
      submitFormData(userData)
        .then(response => {
          showSuccessMessage('Compte créé avec succès !');
          form.reset();
        })
        .catch(error => {
          showErrorMessage('Échec de la création du compte. Veuillez réessayer.');
        });
    }
  });
  
  function validateForm() {
    // Effacer les erreurs précédentes
    clearErrors();
    
    let isValid = true;
    const username = form.elements.username;
    const email = form.elements.email;
    const password = form.elements.password;
    
    // Valider le nom d'utilisateur
    if (username.value.trim() === '') {
      displayError(username, 'Le nom d\'utilisateur est requis');
      isValid = false;
    } else if (username.value.length < 3) {
      displayError(username, 'Le nom d\'utilisateur doit contenir au moins 3 caractères');
      isValid = false;
    }
    
    // Valider l'email
    if (email.value.trim() === '') {
      displayError(email, 'L\'email est requis');
      isValid = false;
    } else if (!isValidEmail(email.value)) {
      displayError(email, 'Veuillez saisir une adresse email valide');
      isValid = false;
    }
    
    // Valider le mot de passe
    if (password.value === '') {
      displayError(password, 'Le mot de passe est requis');
      isValid = false;
    } else if (password.value.length < 8) {
      displayError(password, 'Le mot de passe doit contenir au moins 8 caractères');
      isValid = false;
    } else if (!/[A-Z]/.test(password.value) || !/[a-z]/.test(password.value) || !/[0-9]/.test(password.value)) {
      displayError(password, 'Le mot de passe doit inclure majuscules, minuscules et chiffres');
      isValid = false;
    }
    
    return isValid;
  }
  
  function setupRealTimeValidation() {
    const inputs = form.querySelectorAll('input');
    
    inputs.forEach(input => {
      input.addEventListener('input', function() {
        // Effacer l'erreur quand l'utilisateur commence à taper
        const errorElement = this.parentElement.querySelector('.error-message');
        if (errorElement) {
          errorElement.remove();
          this.classList.remove('error-input');
        }
      });
    });
    
    // Validation spécifique à l'email
    form.elements.email.addEventListener('blur', function() {
      if (this.value && !isValidEmail(this.value)) {
        displayError(this, 'Veuillez saisir une adresse email valide');
      }
    });
  }
  
  // Fonctions utilitaires
  function isValidEmail(email) {
    return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email);
  }
  
  function displayError(input, message) {
    const formControl = input.parentElement;
    const errorElement = document.createElement('div');
    errorElement.className = 'error-message';
    errorElement.textContent = message;
    formControl.appendChild(errorElement);
    input.classList.add('error-input');
  }
  
  function clearErrors() {
    document.querySelectorAll('.error-message').forEach(error => error.remove());
    document.querySelectorAll('.error-input').forEach(input => {
      input.classList.remove('error-input');
    });
  }
  
  function showSuccessMessage(message) {
    const messageElement = document.createElement('div');
    messageElement.className = 'success-message';
    messageElement.textContent = message;
    form.parentElement.insertBefore(messageElement, form);
    
    // Supprimer après 3 secondes
    setTimeout(() => {
      messageElement.remove();
    }, 3000);
  }
  
  function showErrorMessage(message) {
    const messageElement = document.createElement('div');
    messageElement.className = 'error-banner';
    messageElement.textContent = message;
    form.parentElement.insertBefore(messageElement, form);
    
    // Supprimer après 3 secondes
    setTimeout(() => {
      messageElement.remove();
    }, 3000);
  }
  
  // Simuler une soumission API
  function submitFormData(data) {
    return new Promise((resolve, reject) => {
      // Simuler une requête réseau
      setTimeout(() => {
        // Taux de succès de 90% pour la démo
        if (Math.random() > 0.1) {
          resolve({ success: true, message: 'Utilisateur créé' });
        } else {
          reject({ success: false, message: 'Erreur serveur' });
        }
      }, 1500);
    });
  }
});

Considérations d’Accessibilité des Formulaires

Lors de la gestion des formulaires avec JavaScript, assurez-vous qu’ils restent accessibles :

  1. Maintenir la gestion du focus : Lors de l’affichage d’erreurs, définir le focus sur le premier champ invalide
  2. Utiliser les attributs ARIA : Ajouter aria-invalid="true" aux champs invalides
  3. Associer les messages d’erreur : Utiliser aria-describedby pour connecter les entrées avec leurs messages d’erreur
  4. Fournir des instructions claires : Utiliser les éléments <label> et des messages d’erreur descriptifs
  5. Supporter la navigation au clavier : S’assurer que tous les contrôles de formulaire sont accessibles au clavier

Exemple de gestion d’erreur accessible :

function displayError(input, message) {
  const formControl = input.parentElement;
  const errorId = `${input.id}-error`;
  
  const errorElement = document.createElement('div');
  errorElement.id = errorId;
  errorElement.className = 'error-message';
  errorElement.textContent = message;
  
  formControl.appendChild(errorElement);
  
  // Ajouter les attributs d'accessibilité
  input.setAttribute('aria-invalid', 'true');
  input.setAttribute('aria-describedby', errorId);
  
  // Définir le focus sur la première entrée invalide
  if (!document.querySelector('.error-input')) {
    input.focus();
  }
  
  input.classList.add('error-input');
}

FAQ

Utilisez la méthode reset intégrée sur l'élément formulaire : document.getElementById('myForm').reset();

Utilisez la méthode checkValidity de l'API de Validation par Contraintes : const isValid = form.checkValidity();

Pour soumettre des données de formulaire de manière asynchrone, utilisez l'API Fetch avec l'objet FormData. D'abord, créez une instance FormData à partir de votre formulaire. Ensuite, envoyez-la en utilisant fetch avec la méthode POST. Assurez-vous de gérer la réponse et d'intercepter toute erreur lors de la soumission.

Pour gérer les téléchargements de fichiers, accédez à la propriété files de l'élément input file, récupérez le fichier sélectionné, et ajoutez-le à un objet FormData avant de le soumettre en utilisant fetch ou une autre méthode.

L'événement `input` se déclenche chaque fois que la valeur d'entrée change, tandis que l'événement `change` ne se déclenche que lorsque l'entrée perd le focus et que la valeur a changé depuis qu'elle a obtenu le focus.

Pour ajouter dynamiquement des champs de formulaire, créez de nouveaux éléments input en utilisant document.createElement, définissez leur type et nom, et ajoutez-les à un élément conteneur dans le formulaire.

Conclusion

En maîtrisant la gestion des formulaires avec JavaScript vanilla, vous obtenez un contrôle total sur vos formulaires sans dépendre de bibliothèques externes. Cette approche réduit les dépendances, améliore les performances et approfondit votre compréhension du fonctionnement réel des formulaires web.

Listen to your bugs 🧘, with OpenReplay

See how users use your app and resolve issues fast.
Loved by thousands of developers