← Blog

Comment construire en React un formulaire d’adresse qui fonctionne dans tous les pays

Un formulaire d’adresse américain avec une liste déroulante de pays n’est pas international. Champs par pays, codes postaux, tokens d’autofill, recherche d’adresse et erreurs en React.

Preet Suthar · · 6 min de lecture

  • React
  • Forms
  • E-commerce
  • Accessibility

La plupart des formulaires d’adresse sont un formulaire d’adresse américain avec une liste déroulante de pays au-dessus. Ville, État, code ZIP, dans cet ordre, pour tout le monde. Résultat : un acheteur à Londres n’a pas d’État à choisir, un acheteur à Berlin tape le code postal avant la ville par habitude, et un acheteur à Tokyo doit écrire son adresse à l’envers.

Un formulaire d’adresse est le formulaire le plus long de la plupart des boutiques, et c’est là que se rencontrent l’autofill, la validation et les utilisateurs internationaux. Voici comment en construire un en React qui fonctionne dans tous les pays où vous livrez.

Le pays d’abord, puis la mise en page

Le pays détermine quels champs existent, comment ils s’appellent, lesquels sont obligatoires et dans quel ordre ils apparaissent. Demandez donc le pays en premier, présélectionné à partir de la locale ou de l’IP de l’acheteur, et construisez le reste à partir de données.

Quelques exemples de tout ce qui change :

PaysChamps après la rueRégionCode postal
États-UnisVille, État, Code ZIPObligatoire12345 ou 12345-6789
Royaume-UniVille, Code postalAucunePar exemple SW1A 1AA
AllemagneCode postal, VilleAucune5 chiffres
JaponCode postal, Préfecture, VilleObligatoire123-4567
CanadaVille, Province, Code postalObligatoirePar exemple K1A 0B1

Vous n’avez pas besoin d’étudier chaque pays à la main. Google publie les métadonnées d’adresse sur lesquelles repose sa bibliothèque libaddressinput, avec l’ordre des champs, les libellés, les champs obligatoires et les formats de code postal pour la plupart des pays du monde. Choisissez les pays où vous livrez le plus et donnez-leur un format exact, puis donnez à tous les autres un format de repli simple : deux lignes d’adresse, ville, région et code postal, sans validation stricte.

type Field = "address1" | "address2" | "city" | "region" | "postalCode"

type CountryFormat = {
  rows: Field[][]
  labels: Partial<Record<Field, string>>
  required: Field[]
  postalCode?: { pattern: RegExp; example: string }
  regions?: { code: string; name: string }[]
}

const countryFormats: Record<string, CountryFormat> = {
  US: {
    rows: [["address1"], ["address2"], ["city", "region", "postalCode"]],
    labels: { region: "State", postalCode: "ZIP code" },
    required: ["address1", "city", "region", "postalCode"],
    postalCode: { pattern: /^\d{5}(-\d{4})?$/, example: "94110" },
  },
  GB: {
    rows: [["address1"], ["address2"], ["city"], ["postalCode"]],
    labels: { city: "Town or city", postalCode: "Postcode" },
    required: ["address1", "city", "postalCode"],
    postalCode: {
      pattern: /^[A-Z]{1,2}\d[A-Z\d]? ?\d[A-Z]{2}$/i,
      example: "SW1A 1AA",
    },
  },
}

Le composant de formulaire affiche ensuite format.rows et ne mentionne jamais un pays par son nom.

Moins de champs

Chaque champ affiché est une chose de plus à remplir et une chose de plus à mal remplir.

  • Un seul champ pour le nom. « Nom complet », pas prénom et nom. Beaucoup de noms ne se découpent pas en deux parties, et l’ordre varie d’un pays à l’autre.
  • La ligne 2 derrière un lien. « Ajouter un appartement, un bâtiment, etc. » l’ouvre. La plupart des gens n’en ont pas besoin. Si l’autofill ou la recherche d’adresse la remplit, affichez-la.
  • L’entreprise derrière un lien aussi, pour les quelques commandes B2B.
  • Téléphone facultatif, avec la raison. « Uniquement pour les questions de livraison » sous le champ récolte plus de numéros qu’un champ obligatoire n’en récolte de vrais.

L’autofill fait l’essentiel du travail

L’autofill du navigateur peut remplir tout le formulaire en une touche, mais seulement si chaque input a un name et le bon token autocomplete. Préfixez les tokens par shipping ou billing pour que le navigateur sache quelle adresse enregistrée va où :

<Input name="name" autoComplete="shipping name" />
<Input name="address1" autoComplete="shipping address-line1" />
<Input name="address2" autoComplete="shipping address-line2" />
<Input name="city" autoComplete="shipping address-level2" />
<Input name="region" autoComplete="shipping address-level1" />
<Input
  name="postalCode"
  autoComplete="shipping postal-code"
  inputMode={country === "US" ? "numeric" : "text"}
/>
<Input name="phone" type="tel" autoComplete="shipping tel" />

address-level1 correspond à l’État, la province ou la préfecture, et address-level2 à la ville. Quand l’adresse de facturation diffère de celle de livraison, affichez un second formulaire avec des tokens billing, pour que le navigateur ne remplisse pas le formulaire de facturation avec l’adresse de livraison.

N’utilisez pas type="number" pour les codes postaux. Les codes ZIP commencent parfois par des zéros, les codes britanniques et canadiens contiennent des lettres, et les inputs numériques arrivent avec des flèches d’incrémentation et des changements à la molette. Utilisez un input texte avec inputMode="numeric" uniquement là où les codes ne sont faits que de chiffres.

Recherche par code postal

Dans certains pays, le code postal indique déjà la ville et la région. Le Japon est le cas typique : les adresses commencent par le code postal, et le code seul identifie la préfecture et la ville. Quand l’acheteur a fini de saisir le code postal, recherchez-le et remplissez la ville et la région, mais n’écrasez jamais ce qu’il a déjà tapé. Sa saisie l’emporte sur vos données.

La recherche d’adresse, où l’on tape le début d’une adresse puis choisit une suggestion, est plus rapide que n’importe quel formulaire sur mobile. Google Places et Mapbox la proposent tous deux sous forme de deux appels : l’un suggère des adresses pour ce qui a été tapé, l’autre transforme la suggestion choisie en champs structurés.

Quelques règles pour le câblage :

  • Attendez une pause dans la saisie et annulez la requête précédente, comme pour n’importe quel champ de recherche.
  • Terminez toujours la liste par « Saisir l’adresse manuellement ». La rue est peut-être récente, ou la suggestion peut être fausse.
  • Après un choix, remplissez les champs et affichez-les, pour que l’acheteur puisse vérifier le résultat et ajouter un numéro d’appartement.
  • L’API Places de Google utilise des tokens de session pour regrouper les appels de suggestion et de détails d’une même recherche. Utilisez-les, sinon les appels risquent d’être facturés séparément.

Des erreurs qui disent ce qui ne va pas

Validez un champ quand l’acheteur le quitte, puis en direct pendant la saisie jusqu’à ce qu’il soit corrigé. Rédigez l’erreur selon le pays : « Saisissez un code ZIP à 5 chiffres » aux États-Unis, « Saisissez un code postal comme SW1A 1AA » au Royaume-Uni. « Code postal invalide » n’aide personne.

À l’envoi, listez chaque problème dans un récapitulatif en haut du formulaire, reliez chacun à son champ et déplacez le focus sur le récapitulatif. Associez chaque erreur à son input avec aria-describedby et définissez aria-invalid, pour que les lecteurs d’écran lisent le message avec le champ.

Normalisez avant de valider : supprimez les espaces superflus, mettez en majuscules les codes postaux britanniques et canadiens, et acceptez-les avec ou sans espace. Rejeter « sw1a1aa » alors que vous pourriez le corriger, c’est votre bug, pas celui de l’acheteur.

Changer de pays

Les gens changent de pays après avoir tapé la moitié de l’adresse plus souvent qu’on ne le croit. Quand ça arrive, gardez ce qui convient encore (nom, lignes de rue, téléphone), videz la région si le nouveau pays a une autre liste, et ne revérifiez que les champs déjà touchés. Afficher de nouvelles erreurs sur des champs qu’ils n’ont pas encore atteints, c’est comme se faire gronder pour quelque chose qu’on n’a pas fait.

Stocker la structure, pas la chaîne

Enregistrez l’adresse sous forme de champs plus un code pays ISO, pas sous forme de lignes formatées. Vous aurez besoin de la structure pour les taxes, les tarifs de livraison et les étiquettes des transporteurs, et vous pourrez toujours la formater pour l’affichage. Un résumé sur une ligne comme « 12 Mission St, San Francisco, CA 94110 » est une vue des données, pas les données.

Une checklist

  • Le pays d’abord, puis les champs, les libellés et l’ordre selon un format propre à chaque pays.
  • Un format exact pour vos principaux pays et un format de repli tolérant pour les autres.
  • Un seul champ de nom, la ligne 2 et l’entreprise derrière des liens, le téléphone facultatif avec une raison.
  • Un name et un token d’autocomplete shipping ou billing sur chaque input.
  • Des inputs texte pour les codes postaux, des claviers numériques uniquement là où les codes sont des chiffres.
  • Une recherche par code postal qui n’écrase jamais les valeurs saisies.
  • Recherche d’adresse avec une option de saisie manuelle en fin de liste.
  • Des messages d’erreur adaptés au pays et un récapitulatif avec liens à l’envoi.

Le bloc HextaUI pour ça

Le bloc Address Form de HextaUI Pro est construit sur ces règles. Seize pays ont leur propre format avec libellés, champs obligatoires, listes de régions et règles postales, et tous les autres pays ont un format de repli simple. Chaque input a le bon token d’autocomplete avec un préfixe shipping ou billing. onSearchAddress et onResolveAddress branchent la recherche d’adresse, avec un exemple pour Google Places, et ces deux mêmes appels se transposent à Mapbox. onLookupPostalCode remplit la ville et la région sans rien écraser de ce qui a été tapé, et validate() liste chaque problème dans un récapitulatif avec liens. SavedAddresses et AddressSummary couvrent les acheteurs connectés et la ligne « Livrer à » une fois terminée.

Le bloc Checkout l’utilise pour la livraison. Si vous construisez le reste de cette page, j’ai aussi écrit un article sur un checkout en une page en React et Next.js.

FAQ

Le champ pays doit-il venir en premier ? Oui. Il détermine quels champs existent et dans quel ordre ils apparaissent, il doit donc être choisi avant que le reste ait un sens.

Faut-il des champs prénom et nom séparés ? Utilisez un seul champ de nom complet, sauf si un transporteur ou un prestataire de paiement exige la séparation.

Quel type d’input pour un code postal ? Un input texte, avec inputMode="numeric" uniquement pour les pays dont les codes ne contiennent que des chiffres.

Ai-je besoin d’une validation d’adresse par API ? Elle aide, mais ne bloquez pas la commande à cause d’elle. Suggérez une correction et laissez l’acheteur garder ce qu’il a saisi.