A better card payment form

25 June, 2014

Card forms are a real pain point on the web. Oftentimes they can be tricky to use and are easy to make mistakes on. Credit card forms are a very sensitive part of the checkout process, and any errors can lead to customer frustratation and potential mistrust.

Well built credit card forms, on the other hand, will speed along the process and vastly reduce errors; both of which are great for business. Improving the usability and experience of a card form can be done by leveraging some HTML5 and a JavaScript library.

These are the things I like to look at:

  1. Ordering the inputs Card number first, expiry second and CVC last. It’s intuitive as this is the order the eye physically scans them on the card.

  2. Providing input placeholders Provide formatted placeholders so people know what to type in and how many characters long it should be.

  3. Favouring text inputs over select dropdowns If possible, use a text input for the expiry date, so people don’t have to jump between gestures or mouse and keyboard on the select menu.

  4. Combining the expiry into one text input To minimise the cognitive load when looking at the form. The expiry is usually joined up together on the card, and should follow this pattern on the web too.

  5. Using the numerical mm/yy format for expiry dates This is the way it most commonly appears on cards. Converting a month number into a month name can be difficult for some people.

  6. Utilise HTML5 input types where possible So a numerical keypad is displayed to mobiles and tablets.

  7. Validating the inputs on the client side Sending an incomplete form off to the server could potentially clear the inputs or instill slight anxiety that payment could have already been made.

  8. Highlighting valid inputs Highlight correctly completed card number, expiry or CVC inputs with a differently coloured border or shadow.

  9. Remove the select card type menu This is not required by the card networks to process the payment. If you can remove it, then do.

  10. Showing a card icon Show an icon that changes depending on what card is being used. A useful cue to let people know they’re on the right path.

  11. Not taking more information than is necessary Card networks only require a card number, expiry and CVC to process a payment — Stripe only require these three essentials, however others may also require a name.

Card payment form demo

Here’s an example of these practices put together:

$(function() {

  $('.cc-num').payment('formatCardNumber');
  $('.cc-exp').payment('formatCardExpiry');
  $('.cc-cvc').payment('formatCardCVC');

  var validateDetails = function() {

    var expiry = $('.cc-exp').payment('cardExpiryVal');
    var validateExpiry = $.payment.validateCardExpiry(expiry["month"], expiry["year"]);
    var validateCVC = $.payment.validateCardCVC($('.cc-cvc').val());

    if (validateExpiry) {
      $('.cc-exp__demo').addClass('identified');
    } else {
      $('.cc-exp__demo').removeClass('identified');
    }

    if (validateCVC) {
      $('.cc-cvc__demo').addClass('identified');
    } else {
      $('.cc-cvc__demo').removeClass('identified');
    }

  }

  $('.paymentInput').bind('change paste keyup', function() {
    validateDetails();
  });

});

Leveraging jQuery.payment for building card forms

jQuery.payment (by Stripe) is “a general purpose library for building credit card forms, validating input, and formatting numbers”. It provides an API of functions that are straightforward to use and can be used for any type of card form, whether it be Stripe, Braintree, Paymill or just about anything else.

For example, this function formats the card number and CVC:

$('.cc-num').payment('formatCardNumber');
$('.cc-cvc').payment('formatCardCVC');

Some useful classes are applied to the input.cc-num element that let us determine the card type, and whether the card is valid or not.

/* when the card is identified, add a green border */
.cc-num.identified{
  border-color:#2ecc71;
}

/* when the card is identified on focus, make the box-shadow glow green too */
.cc-num.identified:focus{
  border-color:#2ecc71;
  box-shadow: 0 0 .1875em #2ecc71;
}

/* style the blank card element */
.card {
  position:absolute;
  display:block;
  right:.375em;
  top:50%;
  margin-top:-10px;
  width:28px;
  height:19px;
  background:url('img/card.png') no-repeat center center;
  background-size: 100%;
}

/* replace the blank card with the card type */
.cc-num.visa + .card{
  background-image:url('img/visa.png');
}

Finally, we can combine the expiry into one text input and separate it out again in JavaScript.

The input can handle both yy and yyyy formats for the year:

// format the expiry input to mm/yy format
$('input.cc-exp').payment('formatCardExpiry');
// use cardExpiryVal to parse and separate out the month and year
var expiry = $('input.cc-exp').payment('cardExpiryVal');
// fetch the month and year from the expiry object
var expiry_month: expiry["month"];
var expiry_year: expiry["year"];

Credits