requestAutocomplete

Prenez mon argent, pas mon temps

Jake Archibald
Jake Archibald

Introduction

J'aime le Web. Dans l'ensemble, je pense que c'est une bonne idée. Je me retrouve donc souvent à débattre entre le Web et les applications natives. L'autre personne ne tarde pas à parler de la facilité des paiements via les systèmes natifs. Ma réponse habituelle est de lancer une bombe fumigène et de courir hors de la pièce en riant de manière hystérique, car je ne peux pas gagner cet argument. Le taux d'abandon de panier sur le Web mobile peut atteindre 97%. Imaginez cela dans le monde réel. Imaginez que 97% des clients d'un supermarché, avec un panier rempli de produits qu'ils souhaitent acheter, le retournent et sortent du magasin. Certains d'entre eux ne font que gonfler les prix et n'ont jamais eu l'intention d'acheter, mais l'expérience utilisateur horrible de l'achat sur le Web y contribue largement. Nous imposons aux utilisateurs une taxe sur leur santé mentale. Pensez à une expérience de paiement agréable que vous avez vécue sur le Web, en particulier sur mobile. Il s'agit d'une plate-forme de téléchargement d'applications, n'est-ce pas ? ou d'un système fermé similaire qui dispose déjà de vos informations de paiement. C'est un problème. Les sites doivent s'engager auprès d'un fournisseur de paiement particulier auprès duquel l'utilisateur doit déjà disposer d'un compte et être connecté, ou auprès d'une plate-forme qui exige que les utilisateurs soient connectés à un fournisseur de paiement particulier, comme une plate-forme de téléchargement d'applications qui vous oblige à coder uniquement pour cette plate-forme. Si vous ne faites pas l'une de ces choses, l'utilisateur sera condamné à appuyer sur son écran ou son clavier jusqu'à ce que la peau de ses doigts soit complètement lisse ou qu'il abandonne. Nous devons y remédier.

requestAutocomplete

Dans un monde où l'on trouve WebGL, WebRTC et d'autres API Web sophistiquées commençant par "Web", requestAutocomplete est plutôt peu glamour. Cependant, il s'agit d'un super-héros vêtu de beige. Une API minuscule et ennuyeuse qui peut planter un pieu dans le cœur du vampire du temps des paiements sur le Web.

Plutôt que de s'appuyer sur un fournisseur de paiement particulier, le site demande les informations de paiement au navigateur, qui les stocke au nom de l'utilisateur. La version de requestAutocomplete() de Chrome s'intègre également à Google Wallet pour les utilisateurs situés aux États-Unis uniquement (actuellement). Essayez-les sur notre site de test.

form.requestAutocomplete

Les éléments de formulaire ne comportent qu'une seule nouvelle méthode, requestAutocomplete, qui demande au navigateur de renseigner le formulaire. Le navigateur affiche une boîte de dialogue pour demander l'autorisation à l'utilisateur et lui permettre de sélectionner les informations qu'il souhaite fournir. Vous ne pouvez pas l'appeler quand vous le souhaitez. Il doit être appelé lors de l'exécution d'événements d'interaction particuliers, tels que les événements de souris vers le haut/vers le bas, de clic, de touche et de contact. Il s'agit d'une restriction de sécurité délibérée.

button.addEventListener('click', function(event) {
  form.requestAutocomplete();
  event.preventDefault();
});

// TODO: listen for autocomplete events on the form

Avant d'examiner les événements, nous devons nous assurer que le navigateur comprend vos champs de formulaire.

Exigences concernant les formulaires

À l'époque où Internet était en noir et blanc, Internet Explorer 5 a adopté un nouvel attribut, autocomplete, sur les éléments de saisie de formulaire. Il pouvait être défini sur "Désactivé" pour empêcher le navigateur de proposer des suggestions. Cette API a été étendue afin que vous puissiez spécifier le contenu attendu du champ sans modifier l'attribut "name". C'est ce que requestAutocomplete utilise pour associer les champs de formulaire aux données utilisateur.

<input name="fullname" autocomplete="name">

En tant que spécification, requestAutocomplete n'est pas spécifique aux paiements, mais l'implémentation actuelle de Chrome l'est presque. À l'avenir, les navigateurs devraient pouvoir gérer d'autres types de données, comme les identifiants de connexion et le générateur de mots de passe, les informations de passeport et même l'importation d'un avatar.

Actuellement, dans Chrome, requestAutocomplete reconnaît les éléments suivants:

Paiement

  • e-mail
  • cc-name - nom sur la carte
  • cc-number - numéro de carte
  • cc-exp-month : mois d'expiration de la carte (deux chiffres)
  • cc-exp-year : année d'expiration de la carte au format à quatre chiffres
  • cc-csc : code de sécurité de la carte à trois ou quatre chiffres
<input type="email" autocomplete="email" name="email">
<input type="text" autocomplete="cc-name" name="card-name">
<input type="text" autocomplete="cc-number" name="card-num">
<input type="text" autocomplete="cc-exp-month" name="card-exp-month">
<input type="text" autocomplete="cc-exp-year" name="card-exp-year">
<input type="text" autocomplete="cc-csc" name="card-csc">

Les attributs "name" que j'ai utilisés ci-dessus ne sont que des exemples. Vous n'êtes pas obligé d'utiliser des valeurs particulières. Si vous comptez réutiliser ce formulaire pour les utilisateurs sans requestAutocomplete, ce qui est idéal, vous devez ajouter des libellés, une mise en page et une validation HTML5 de base.

Vous n'êtes pas limité aux éléments de saisie. Vous pouvez utiliser n'importe quel type d'entrée de formulaire. Par exemple, vous pouvez utiliser <select> pour les champs d'expiration de la carte.

Message détaillé de la console.
Message de console détaillé

Adresse

  • name - nom complet. Il est préférable de saisir un nom complet dans un seul champ plutôt que dans plusieurs. Plusieurs champs, tels que le prénom et le nom, présentent un biais occidental et peuvent ne pas avoir de sens pour d'autres cultures. De plus, il est plus facile de saisir des informations dans un seul champ.

  • tel : numéro de téléphone complet, y compris le code pays. Il peut également être décomposé en :

    • tel-country-code (par exemple, +44)
    • tel-national - the rest
  • street-address : adresse complète avec les composants séparés par une virgule, peut être décomposée en

    • address-line1
    • address-line2 : peut être vide
  • localité - ville

  • region : code de l'État, du comté ou du canton

  • postal-code - Code postal, code postal, code postal

  • country

Les éléments ci-dessus doivent être utilisés avec les éléments suivants : - facturation - livraison

<input type="text" autocomplete="billing name" required name="billing-name">
<input type="tel" autocomplete="billing tel" required name="billling-tel">
<input type="text" autocomplete="billing address-line1" required name="billing-address1">
<input type="text" autocomplete="billing address-line2" required name="billing-address2">
<input type="text" autocomplete="billing locality" required name="billing-locality">
<input type="text" autocomplete="billing region" required name="billing-region">
<input type="text" autocomplete="billing postal-code" required name="billing-postal-code">
<select autocomplete="billing country" required name="billing-country">
  <option value="US">United States</option>
  …
</select>

<input type="text" autocomplete="shipping name" name="shipping-name">
…

Encore une fois, les attributs de nom sont des exemples. Vous pouvez utiliser ceux de votre choix. Évidemment, tous les formulaires ne doivent pas demander une adresse de livraison. Par exemple, ne me demandez pas où je voudrais que mon hôtel me livre mon colis, car son emplacement actuel est souvent le point de vente. Nous avons donc notre formulaire et nous savons comment demander autocompletion. Mais…

Quand doit-on appeler requestAutocomplete ?

Dans l'idéal, vous devez afficher la boîte de dialogue requestAutocomplete au lieu de charger la page qui affiche le formulaire de paiement. Si tout se passe bien, l'utilisateur ne devrait pas voir le formulaire du tout.

Flux de paiements

Un modèle courant consiste à avoir une page de panier avec un bouton "Paiement" qui vous redirige vers le formulaire de paiement. Dans ce cas, vous souhaitez charger votre formulaire de facturation sur la page du panier, mais le masquer à l'utilisateur et appeler requestAutocomplete dessus lorsque l'utilisateur appuie sur le bouton "Paiement". N'oubliez pas que vous devez diffuser votre page de panier via SSL pour éviter l'avertissement Skeletor. Pour commencer, nous devons masquer le bouton de paiement afin que l'utilisateur ne puisse pas cliquer dessus tant que nous ne sommes pas prêts. Toutefois, nous ne voulons le faire que pour les utilisateurs disposant de JavaScript. Dans l'en-tête de votre page:

<script>document.documentElement.className += ' js';</script>

Et dans votre CSS:

.js #checkout-button,
#checkout-form.for-autocomplete {
  display: none;
}

Nous devons inclure le formulaire de facturation sur la page du panier. Il peut être placé n'importe où. Le CSS ci-dessus garantit qu'il n'est pas visible par l'utilisateur.

<form id="checkout-form" class="for-autocomplete" action="/checkout" method="post">
  …fields for payment, billing address &amp; shipping if relevant…
</form>

Notre code JavaScript peut maintenant commencer à tout configurer:

function enhanceForm() {
  var button = document.getElementById('checkout-button');
  var form = document.getElementById('checkout-form');

  // show the checkout button
  button.style.display = 'block';

  // exit early if there's no requestAutocomplete support
  if (!form.requestAutocomplete) {
    // be sure to show the checkout button so users can
    // access the basic payment form!
    return;
  }

  button.addEventListener('click', function(event) {
    form.requestAutocomplete();
    event.preventDefault();
  });

  // TODO: listen for autocomplete events on the form
}

Vous devez appeler enhanceForm sur la page du panier, un certain temps après votre formulaire et votre bouton de paiement. Les navigateurs compatibles avec requestAutocomplete bénéficieront de la nouvelle expérience rapide, tandis que les autres utiliseront votre formulaire de paiement habituel. Pour gagner des points supplémentaires, vous pouvez charger le code HTML du formulaire via XHR dans le cadre de enhanceForm. Cela signifie que vous ne pouvez charger le formulaire que dans les navigateurs compatibles avec requestAutocomplete. Vous n'avez pas besoin de vous souvenir d'ajouter le formulaire à chaque page à partir de laquelle vous pouvez appeler enhanceForm. C'est ainsi que fonctionne le site de démonstration.

Vous avez appelé requestAutocomplete. Que faire maintenant ?

Le processus de saisie semi-automatique est asynchrone. requestAutocomplete est renvoyé immédiatement. Pour savoir comment cela s'est passé, nous écoutons quelques nouveaux événements:

form.addEventListener('autocomplete', function() {
  // hurrah! You got all the data you needed
});

form.addEventListener('autocompleteerror', function(event) {
  if (event.reason == 'invalid') {
    // the form was populated, but it failed html5 validation
    // eg, the data didn't match one of your pattern attributes
  }
  else if (event.reason == 'cancel') {
    // the user aborted the process
  }
  else if (event.reason == 'disabled') {
    // the browser supports requestAutocomplete, but it's not
    // available at this time. Eg, it wasn't called from an
    // interaction event or the page is insecure
  }
});

Si tout a fonctionné, vous pouvez faire ce que vous voulez avec les données. Le plus simple est d'envoyer le formulaire. Le serveur peut ensuite valider les données et fournir à l'utilisateur une page de confirmation incluant les frais de livraison. Si les données sont non valides, vous pouvez afficher le formulaire et mettre en surbrillance les champs que l'utilisateur doit modifier. Vous pouvez également simplement envoyer le formulaire et laisser votre validation côté serveur habituelle prendre le relais. Si l'utilisateur a annulé le processus, vous n'avez rien à faire. Si la fonctionnalité est désactivée, redirigez l'utilisateur vers le formulaire standard. Dans la plupart des cas, vos auditeurs ressembleront à ceci :

form.addEventListener('autocomplete', function() {
  form.submit();
});

form.addEventListener('autocompleteerror', function(event) {
  if (event.reason == 'invalid') {
    form.submit();
  }
  else if (event.reason != 'cancel') {
    window.location = '/checkout-page/';
  }
});

Où le navigateur stocke-t-il mes données ?

La spécification ne dicte pas l'emplacement de stockage des données, ce qui permet aux navigateurs d'innover. Si vous êtes connecté à Chrome, vous pouvez stocker des informations dans Google Wallet pour les rendre accessibles sur d'autres appareils sur lesquels vous êtes connecté. Si vous stockez vos informations dans Wallet, votre numéro de carte réel ne sera pas distribué par requestAutocomplete, ce qui renforce la sécurité. Si vous n'êtes pas connecté à Chrome ou si vous choisissez de ne pas utiliser Google Wallet, vos informations peuvent être stockées localement dans le navigateur pour être réutilisées. C'est l'état actuel des choses, mais Chrome et d'autres navigateurs pourraient adopter d'autres fournisseurs de paiement à l'avenir.

Faciliter les paiements

Il est assez ridicule que les utilisateurs doivent saisir leurs informations de paiement encore et encore chaque fois qu'ils souhaitent effectuer un achat. Les choses sont plus simples lorsqu'un site stocke vos informations de paiement. Je suis un peu inquiet du nombre de sites qui stockent les informations de ma carte. C'est un problème idéal à résoudre avec les normes Web. requestAutocomplete peut proposer des paiements en un clic sur l'ensemble du Web, sans service ni plate-forme de verrouillage. Il était temps !

Bonus: Gérer les formulaires multipages

Il est préférable d'appeler requestAutocomplete une seule fois et de collecter toutes les données dont vous avez besoin. Si vous ne pouvez pas modifier votre serveur pour qu'il reçoive toutes ces données en même temps, ce n'est pas grave. Extrayez les données du formulaire rempli et envoyez-les de la manière qui vous convient le mieux. Vous pouvez utiliser cette petite fonction pratique pour capturer toutes les données actuellement prises en charge en tant qu'objet simple, sans avoir à créer vous-même un formulaire. Une fois que vous avez les données, vous pouvez les transformer dans le format dont votre serveur a besoin et les publier en plusieurs étapes.

checkoutButton.addEventListener('click', function() {
  requestUserData({
    billing: true,
    shipping: true
  }, function(response) {
    if (response.err == 'cancel') {
      // exit silently
      return;
    }
    if (response.err) {
      // fall back to normal form
      window.location.href = '/normal-checkout-form/';
      return;
    }

    // the rest is just made-up pseudo code as an example
    postToServer(data.shipping).then(function() {
      return postToServer(data.billing);
    }).then(function() {
      return postToServer(data.cc);
    }).catch(function() {
      // handle error
    });
  });
});