Retour au cours

frontend / html

Formulaires avancés : types d'inputs et validation native

Leçon 61 exercice

Explication

Ce que vous allez apprendre

  • Choisir le bon type d'<input> (email, date, tel, range...) pour chaque besoin de saisie
  • Utiliser required, min, max, pattern et minlength pour valider sans JavaScript
  • Comprendre pourquoi la validation native n'est jamais suffisante seule côté sécurité
  • Personnaliser un message d'erreur natif avec setCustomValidity()
  • Ajouter de l'autocomplétion légère avec <datalist>

Dans quel contexte ?

Un développeur backend refuse une pull request sur formulaire-inscription.html : le champ téléphone accepte n'importe quelle chaîne de caractères côté client, ce qui envoie des données mal formées à l'API. En ajoutant type="tel" pattern="[0-9]{10}", le navigateur bloque déjà la soumission si le format est incorrect et affiche un message natif, avant même que la requête ne parte vers le serveur. C'est un gain d'UX immédiat, mais qui ne dispense jamais de revalider ce même champ côté API.

Étape 1 : le réflexe à corriger chez le débutant

Beaucoup de développeurs juniors pensent que toute validation de formulaire doit passer par du JavaScript personnalisé. C'est une idée fausse : le navigateur embarque déjà un système de validation complet et gratuit, testé sur des milliards d'appareils.

Étape 2 : un simple changement de type fait déjà beaucoup

Prenons le cas le plus simple. Choisir type="email" plutôt que type="text" n'est pas juste cosmétique : le navigateur adapte automatiquement le clavier virtuel sur mobile, avec le symbole @ accessible directement.

Étape 3 : et ça va plus loin que le clavier

En plus du clavier adapté, chaque type spécialisé affiche une interface dédiée — un sélecteur pour type="date", un curseur pour type="range" — ET valide le format tout seul, sans une seule ligne de JavaScript. Un type d'input, c'est donc trois avantages en un : ergonomie, cohérence visuelle, et validation.

Étape 4 : ajouter des règles précises avec des attributs

Une fois le bon type choisi, on peut affiner avec des attributs comme required, min, max, pattern ou minlength. Le navigateur vérifie automatiquement ces règles au moment de soumettre le formulaire.

Étape 5 : que se passe-t-il si une règle est violée

S'il détecte un problème, le navigateur empêche l'envoi et affiche un message d'erreur natif, positionné directement sous le champ concerné — toujours sans JavaScript. Pour aller plus loin, une API (element.validity) permet même de personnaliser ces messages.

Type d'inputClavier mobile adaptéValidation native intégrée
emailClavier avec @Format email basique
telClavier numériqueAucune (utiliser pattern)
urlClavier avec / et .comFormat URL
numberClavier numériquemin/max/step
dateSélecteur de date natifFormat date valide

Prérequis

Cette leçon suppose que vous maîtrisez déjà les bases des formulaires (<label>, <input>, name) vues à la leçon précédente.

Le piège à connaître avant de continuer

Il reste un point crucial à ne jamais oublier : cette validation native protège l'expérience utilisateur côté navigateur, mais elle ne remplace JAMAIS une validation côté serveur. N'importe qui peut désactiver JavaScript ou envoyer une requête directement à l'API sans passer par le formulaire.

Retenez cette règle simple : la validation HTML améliore l'UX, la validation serveur garantit la sécurité — les deux sont nécessaires, jamais l'une à la place de l'autre.

Piège fréquent

Ne jamais faire confiance uniquement à required ou pattern pour sécuriser une API. N'importe qui peut envoyer une requête POST directement avec curl ou Postman, en contournant totalement le formulaire et sa validation native.

Et ensuite ?

Une fois les formulaires maîtrisés, la prochaine étape consiste à sortir de la "div-ite" en apprenant la sémantique avancée : article, section, nav, aside.

Commandes & code

Formulaires avancés : types d'inputs et validation native

Le navigateur peut valider énormément de choses sans une ligne de JavaScript.

html
<!-- Types d'input spécialisés : chacun adapte le clavier mobile et l'UI -->
<input type="date" name="naissance">
<input type="time" name="heure">
<input type="datetime-local" name="rdv">
<input type="week" name="semaine">
<input type="month" name="mois">

<input type="tel" name="telephone" pattern="[0-9]{10}" placeholder="0600000000">
<input type="url" name="site" placeholder="https://exemple.com">
<input type="search" name="q" placeholder="Rechercher...">

<input type="color" name="couleur" value="#3366ff">

<input type="range" name="volume" min="0" max="100" step="5" value="50">

<input type="file" name="avatar" accept="image/png, image/jpeg" multiple>
html
<!-- Validation native complète, sans JS -->
<form novalidate id="formInscription">
    <label for="pseudo">Pseudo (3-15 caractères)</label>
    <input
        type="text"
        id="pseudo"
        name="pseudo"
        required
        minlength="3"
        maxlength="15"
        pattern="[a-zA-Z0-9_]+"
        title="Lettres, chiffres et underscore uniquement"
    >

    <label for="email">Email professionnel</label>
    <input
        type="email"
        id="email"
        name="email"
        required
        pattern=".+@entreprise\.com$"
    >

    <label for="quantite">Quantité (1 à 10)</label>
    <input type="number" id="quantite" name="quantite" min="1" max="10" step="1" required>

    <button type="submit">Valider</button>
</form>

<script>
// L'API de validation native reste accessible en JS pour des messages custom
const email = document.getElementById("email");

email.addEventListener("invalid", () => {
    if (email.validity.patternMismatch) {
        email.setCustomValidity("Utilisez votre adresse @entreprise.com");
    } else {
        email.setCustomValidity(""); // reset sinon le message reste bloqué
    }
});

email.addEventListener("input", () => email.setCustomValidity(""));
</script>
html
<!-- datalist : autocomplétion native, sans framework -->
<label for="langage">Langage préféré</label>
<input list="langages" id="langage" name="langage">
<datalist id="langages">
    <option value="JavaScript">
    <option value="Python">
    <option value="Rust">
    <option value="Go">
</datalist>

<!-- Attributs de validation transversaux -->
<input type="text" required aria-describedby="aide-pseudo">
<span id="aide-pseudo">3 caractères minimum</span>
Propriété JS (element.validity)Sens
valueMissingchamp requis vide
patternMismatchne respecte pas pattern
rangeOverflow/rangeUnderflowhors de min/max
tooShort/tooLonghors de minlength/maxlength

Résumé

  • Les types d'input spécialisés adaptent automatiquement clavier et UI mobile.
  • pattern, min, max, minlength, maxlength couvrent 80% des besoins de validation.
  • setCustomValidity() personnalise les messages sans réinventer la validation.
  • datalist fournit une autocomplétion native légère.

Exercices pratiques

1 disponible
1

Mission : faire accepter la pull request du champ téléphone

Objectif : Corriger un champ téléphone qui accepte n'importe quelle chaîne, tout en comprenant pourquoi cette correction ne suffit pas côté sécurité.

Contexte

Un développeur backend refuse une pull request sur formulaire-inscription.html : le champ téléphone est un simple <input type="text" name="telephone">, qui accepte n'importe quelle chaîne de caractères et envoie des données mal formées à l'API.

Ta mission : corriger ce champ côté client, puis expliquer les limites de cette correction.

Résoudre l’exercice →