requestAutocomplete

Pegue meu dinheiro, não meu tempo

Jake Archibald
Jake Archibald

Introdução

Eu gosto da Web. No geral, acho que é uma boa ideia. Por isso, participo de muitos debates sobre a Web e apps nativos. Não demora muito para a outra pessoa começar a falar sobre a facilidade de pagamentos por sistemas nativos. Minha resposta usual é soltar uma bomba de fumaça e sair correndo da sala rindo histericamente, porque não é um argumento que eu posso vencer. O abandono do carrinho de compras na Web móvel pode chegar a 97%. Imagine isso no mundo real. Imagine 97% das pessoas em um supermercado, com um carrinho cheio de coisas, deixando-o e indo embora. Algumas dessas pessoas estão apenas pesquisando preços e nunca tiveram a intenção de comprar, mas a experiência horrível do usuário ao comprar na Web é um fator significativo. Estamos cobrando dos usuários um imposto sobre a sanidade deles. Pense em uma experiência de pagamento agradável que você teve na Web, especialmente em dispositivos móveis. É uma app store, certo? Ou pelo menos um sistema fechado semelhante que já tenha suas informações de pagamento. Isso é um problema. Ele exige que os sites se comprometam com um determinado provedor de pagamentos em que o usuário já precisa ter uma conta e fazer login ou se comprometer com uma plataforma que exige que os usuários façam login em um determinado provedor de pagamentos, como uma app store que exige que você programe exclusivamente para essa plataforma. Se você não fizer isso, o usuário vai ficar tocando na tela ou no teclado até que a pele do dedo acabe ou ele desista. Precisamos corrigir isso.

requestAutocomplete

Em um mundo de WebGL, WebRTC e outras APIs da Web que começam com "Web", requestAutocomplete é bastante simples. No entanto, é um super-herói usando roupas bege. Uma API pequena e chata que pode perfurar o coração do vampiro do tempo dos pagamentos na Web.

Em vez de depender de um determinado provedor de pagamentos, o site solicita detalhes de pagamento do navegador, que os armazena em nome do usuário. A versão do Chrome de requestAutocomplete() também se integra à Carteira do Google para somente usuários dos EUA (no momento). Teste no nosso site de testes.

form.requestAutocomplete

Os elementos de formulário têm um único método novo, o requestAutocomplete, que solicita que o navegador preencha o formulário. O navegador vai mostrar uma caixa de diálogo ao usuário pedindo permissão e permitindo que ele selecione quais detalhes gostaria de fornecer. Não é possível chamar esse método quando quiser. Ele precisa ser chamado durante a execução de eventos de interação específicos, como eventos de clique, tecla e toque, e de mouse para cima/para baixo. Essa é uma restrição de segurança deliberada.

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

// TODO: listen for autocomplete events on the form

Antes de analisarmos os eventos, precisamos garantir que o navegador entenda os campos do formulário.

Requisitos do formulário

Quando a Internet era em preto e branco, o Internet Explorer 5 adotou um novo atributo, autocomplete, nos elementos de entrada de formulário. Ele pode ser definido como "desativado" para impedir que o navegador ofereça sugestões. Essa API foi ampliada para que você possa especificar o conteúdo esperado do campo sem modificar o atributo "name". É isso que o requestAutocomplete usa para vincular campos de formulário aos dados do usuário.

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

Como especificação, requestAutocomplete não é específico para pagamentos, mas a implementação atual do Chrome é. No futuro, os navegadores poderão lidar com outros tipos de dados, como detalhes de login e gerador de senha, informações de passaporte e até mesmo o upload de um avatar.

No Chrome, requestAutocomplete reconhece o seguinte:

Pagamento

  • e-mail
  • cc-name - nome como consta no cartão
  • cc-number - número do cartão
  • cc-exp-month: mês de vencimento do cartão com dois dígitos
  • cc-exp-year: ano de vencimento do cartão com quatro dígitos
  • cc-csc - 3-4 digit card security code
<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">

Os atributos "name" usados acima são apenas exemplos. Não é necessário usar valores específicos. Se você for reutilizar esse formulário para usuários sem requestAutocomplete, o que é o ideal, adicione rótulos, layout e validação básica do HTML5.

Você também não está restrito a elementos de entrada. É possível usar qualquer tipo de entrada de formulário. Por exemplo, você pode usar <select> para os campos de validade do cartão.

Mensagem detalhada do console.
Mensagem detalhada do console

Endereço

  • name - nome completo. Usar um nome completo como um único campo é muito melhor do que vários campos. Vários campos, como nome e sobrenome, mostram um viés ocidental e podem não fazer sentido para outras culturas. Além disso, é mais fácil digitar em um único campo.

  • tel: número de telefone completo, incluindo o código do país, que pode ser dividido em

    • tel-country-code - por exemplo, +44
    • tel-national - the rest
  • street-address: endereço completo com componentes separados por vírgulas, pode ser dividido em

    • address-line1
    • address-line2: pode ficar vazio
  • locality - city/town

  • região: código do estado, do condado ou do cantão

  • postal-code: código postal, código postal, CEP

  • país

Use as informações acima em conjunto com: - faturamento - frete

<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">
…

Mais uma vez, os atributos de nome são exemplos. Você pode usar o que quiser. Obviamente, nem todos os formulários precisam solicitar um endereço de entrega. Por exemplo, não me pergunte onde eu gostaria que meu quarto de hotel fosse entregue, porque o local atual é o ponto de venda. Certo, temos o formulário e sabemos como solicitar autocompletion. Mas…

Quando o requestAutocomplete precisa ser chamado?

O ideal é mostrar a caixa de diálogo requestAutocomplete em vez de carregar a página que mostra o formulário de finalização da compra. Se tudo correr bem, o usuário não vai ver o formulário.

Fluxo de pagamentos

Um padrão comum é ter uma página de carrinho com um botão "Finalizar compra" que leva você ao formulário de detalhes de pagamento. Nessa situação, você quer carregar o formulário de faturamento na página do carrinho, mas ocultá-lo do usuário e chamar requestAutocomplete nele quando o usuário clicar no botão "Finalizar compra". Lembre-se de que você precisa veicular a página do carrinho por SSL para evitar o aviso Skeletor. Para começar, precisamos ocultar o botão de finalização da compra para que o usuário não possa clicar nele até que estejamos prontos, mas só queremos fazer isso para usuários com JavaScript. Então, na cabeça da página:

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

E no CSS:

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

Precisamos incluir o formulário de faturamento na página do carrinho. Ele pode ser colocado em qualquer lugar, e o CSS acima garante que ele não fique visível para o usuário.

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

Agora nosso JavaScript pode começar a configurar tudo:

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
}

Você chamaria enhanceForm na página do carrinho, algum tempo depois do formulário e do botão de finalização da compra. Os navegadores compatíveis com requestAutocomplete vão ter a nova experiência rápida, enquanto outros vão usar a forma de pagamento normal. Para pontos extras, carregue o formulário HTML por XHR como parte de enhanceForm. Isso significa que você só pode carregar o formulário em navegadores compatíveis com requestAutocomplete e não precisa adicionar o formulário a cada página que pode chamar enhanceForm. É assim que o site de demonstração funciona.

Você chamou requestAutocomplete. E agora?

O processo de preenchimento automático é assíncrono, e requestAutocomplete é retornado imediatamente. Para descobrir como isso aconteceu, detectamos alguns eventos novos:

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
  }
});

Se tudo funcionar, você poderá fazer o que quiser com os dados. A coisa mais simples a fazer é enviar o formulário. O servidor pode validar os dados e mostrar ao usuário uma página de confirmação com o custo da entrega. Se os dados forem inválidos, mostre o formulário e destaque os campos que o usuário precisa corrigir. Como alternativa, você pode enviar o formulário e deixar que a validação regular do lado do servidor assuma o controle. Se o usuário cancelou o processo, você não precisa fazer nada. Se o recurso estiver desativado, encaminhe o usuário ao formulário normal. Na maioria dos casos, os listeners vão ser muito parecidos com…

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/';
  }
});

Onde o navegador armazena meus dados?

A especificação não determina onde os dados são armazenados, permitindo que os navegadores inovem. Se você estiver conectado no Chrome, terá a opção de armazenar detalhes na Carteira do Google, tornando-os acessíveis em outros dispositivos em que você fez login. Se você armazenar seus dados na Carteira, o número real do cartão não será distribuído por requestAutocomplete, aumentando a segurança. Se você não estiver conectado ao Chrome ou escolher não usar a Carteira do Google, seus detalhes serão armazenados localmente no navegador para reutilização. Essa é a situação atual, mas, no futuro, o Chrome e outros navegadores podem adotar outros provedores de pagamento.

Facilitar os pagamentos

É um pouco ridículo que os usuários precisem inserir as informações de pagamento várias vezes sempre que quiserem fazer uma compra. As coisas ficam mais fáceis quando um site armazena seus detalhes de pagamento. Estou um pouco desconfortável com a quantidade de sites que armazenam os detalhes do meu cartão. Esse é um problema perfeito para os padrões da Web resolverem. O requestAutocomplete pode trazer pagamentos com um clique para toda a Web, sem bloqueio de serviço ou plataforma, e também sobre o tempo!

Rodada bônus: como lidar com formulários de várias páginas

É muito melhor chamar requestAutocomplete uma vez e coletar todos os dados necessários. Se não for possível modificar o servidor para receber todos os dados de uma vez, não tem problema. Pegue os dados do formulário preenchido e envie da maneira que for melhor para você. Você pode usar essa pequena função para capturar todos os dados compatíveis como um objeto simples, sem precisar criar um formulário. Depois de ter os dados, você pode transformá-los em qualquer formato que seu servidor precise e postar em várias etapas.

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
    });
  });
});