JavaScript Credit Card Validation

Overview

This guide covers the following validation aspects:​

  • Card Number Validation using the Luhn Algorithm
  • Card Type Detection (Visa, MasterCard, etc.)
  • Expiry Date Formatting and Validation
  • CVV Validation
  • Real-time Input Formatting

🧪 Implementation

1. Card Number Validation (Luhn Algorithm)

The Luhn Algorithm is a simple checksum formula used to validate identification numbers, such as credit card numbers.​

function isValidCardNumber(number) {
  const sanitized = number.replace(/\D/g, '');
  let sum = 0;
  let shouldDouble = false;

  for (let i = sanitized.length - 1; i >= 0; i--) {
    let digit = parseInt(sanitized.charAt(i), 10);

    if (shouldDouble) {
      digit *= 2;
      if (digit > 9) digit -= 9;
    }

    sum += digit;
    shouldDouble = !shouldDouble;
  }

  return sum % 10 === 0;
}

2. Card Type Detection

Detecting the card type helps in providing specific validations and UI cues.​

function getCardType(number) {
  const sanitized = number.replace(/\D/g, '');

  const cardPatterns = {
    Visa: /^4[0-9]{12}(?:[0-9]{3})?$/,
    MasterCard: /^5[1-5][0-9]{14}$/,
    AmEx: /^3[47][0-9]{13}$/,
    Discover: /^6(?:011|5[0-9]{2})[0-9]{12}$/
  };

  for (const [card, pattern] of Object.entries(cardPatterns)) {
    if (pattern.test(sanitized)) {
      return card;
    }
  }

  return 'Unknown';
}

3. Expiry Date Formatting and Validation

Ensures the expiry date is in MM/YY format and not in the past.

function formatExpiryDate(input) {
  const sanitized = input.replace(/\D/g, '').slice(0, 4);
  if (sanitized.length >= 3) {
    return sanitized.slice(0, 2) + '/' + sanitized.slice(2);
  }
  return sanitized;
}

function isValidExpiryDate(expiry) {
  const [month, year] = expiry.split('/').map(Number);
  if (!month || !year || month < 1 || month > 12) return false;

  const currentDate = new Date();
  const currentYear = currentDate.getFullYear() % 100;
  const currentMonth = currentDate.getMonth() + 1;

  return year > currentYear || (year === currentYear && month >= currentMonth);
}

4. CVV Validation

Validates the CVV based on card type.​

function isValidCVV(cvv, cardType) {
  const sanitized = cvv.replace(/\D/g, '');
  if (cardType === 'AmEx') {
    return /^\d{4}$/.test(sanitized);
  }
  return /^\d{3}$/.test(sanitized);
}

5. Real-time Input Formatting

Formats the card number input in real-time for better readability.​

function formatCardNumber(input) {
  const sanitized = input.replace(/\D/g, '').slice(0, 16);
  return sanitized.replace(/(.{4})/g, '$1 ').trim();
}

🧪 Example Usage

Here’s how you can integrate the above functions into your form:​

<form id="payment-form">
  <label>
    Card Number:
    <input type="text" id="card-number" maxlength="19" placeholder="1234 5678 9012 3456" />
  </label>
  <label>
    Expiry Date:
    <input type="text" id="expiry-date" maxlength="5" placeholder="MM/YY" />
  </label>
  <label>
    CVV:
    <input type="text" id="cvv" maxlength="4" placeholder="123" />
  </label>
  <button type="submit">Submit</button>
</form>
document.getElementById('card-number').addEventListener('input', (e) => {
  e.target.value = formatCardNumber(e.target.value);
});

document.getElementById('expiry-date').addEventListener('input', (e) => {
  e.target.value = formatExpiryDate(e.target.value);
});

document.getElementById('payment-form').addEventListener('submit', (e) => {
  e.preventDefault();

  const cardNumber = document.getElementById('card-number').value;
  const expiryDate = document.getElementById('expiry-date').value;
  const cvv = document.getElementById('cvv').value;

  const cardType = getCardType(cardNumber);

  if (!isValidCardNumber(cardNumber)) {
    alert('Invalid card number.');
    return;
  }

  if (!isValidExpiryDate(expiryDate)) {
    alert('Invalid expiry date.');
    return;
  }

  if (!isValidCVV(cvv, cardType)) {
    alert('Invalid CVV.');
    return;
  }

  alert('Payment details are valid!');
});

Regular Expressions for the most used debit/credit cards

TitleVisa Credit Card
Expression(^4\d{12}$)|(^4[0-8]\d{14}$)|(^(49)[^013]\d{13}$)|(^(49030)[0-1]\d{10}$)|(^(49033)[0-4]\d{10}$)|(^(49110)[^12]\d{10}$)|(^(49117)[0-3]\d{10}$)|(^(49118)[^0-2]\d{10}$)|(^(493)[^6]\d{12}$)
DescriptionMatches Visa Credit Card types 13 or 16 digits starting with 4 including Visa Credit Card, Visa ATM only, Visa Electron and Visa Delta. Safe for international and will NOT match “^(49)” Switch debit cards.
Matches4111111111111111
Non-Matches4903020000000008
 
TitleMaestro Credit Card
Expression(^(5[0678])\d{11,18}$) |(^(6[^0357])\d{11,18}$) |(^(601)[^1]\d{9,16}$) |(^(6011)\d{9,11}$) |(^(6011)\d{13,16}$) |(^(65)\d{11,13}$) |(^(65)\d{15,18}$) |(^(633)[^34](\d{9,16}$)) |(^(6333)[0-4](\d{8,10}$)) |(^(6333)[0-4](\d{12}$)) |(^(6333)[0-4](\d{15}$)) |(^(6333)[5-9](\d{8,10}$)) |(^(6333)[5-9](\d{12}$)) |(^(6333)[5-9](\d{15}$)) |(^(6334)[0-4](\d{8,10}$)) |(^(6334)[0-4](\d{12}$)) |(^(6334)[0-4](\d{15}$)) |(^(67)[^(59)](\d{9,16}$)) |(^(6759)](\d{9,11}$)) |(^(6759)](\d{13}$)) |(^(6759)](\d{16}$)) |(^(67)[^(67)](\d{9,16}$)) |(^(6767)](\d{9,11}$)) |(^(6767)](\d{13}$)) |(^(6767)](\d{16}$))
DescriptionMaestro ONLY card matching – begins with “50” or “56-58” or “6” & 13 to 20 total digits. Overlap of Discover, Solo and Switch is handled and NOT matched.
Matches5600000000000003
Non-Matches6011000000000004
 
TitleMasterCard Credit Card
Expression^5[1-5]\d{14}$
DescriptionMatches MasterCard credit cards. International safe, no overlap with other cards.
Matches5100000000000008
Non-Matches201400000000009
 
TitleDiscover Credit Card
Expression(^(6011)\d{12}$)|(^(65)\d{14}$)
DescriptionDiscover Credit Card matching. International safe, no overlap with other cards.
Matches6011000000000004
Non-Matches4508750000000009
 
TitleAMEX Credit Card
Expression(^3[47])((\d{11}$)|(\d{13}$))
DescriptionAMEX Credit Card match. International safe.
Matches340000000000009
Non-Matches4508750000000009
 
TitleSolo Credit card
Expression(^(6334)[5-9](\d{11}$|\d{13,14}$)) |(^(6767)(\d{12}$|\d{14,15}$))
DescriptionSolo Credit Card match. International safe.
Matches6334500000000003
Non-Matches3528000000000007
 
TitleSwitch Credit Card
Expression(^(49030)[2-9](\d{10}$|\d{12,13}$)) |(^(49033)[5-9](\d{10}$|\d{12,13}$)) |(^(49110)[1-2](\d{10}$|\d{12,13}$)) |(^(49117)[4-9](\d{10}$|\d{12,13}$)) |(^(49118)[0-2](\d{10}$|\d{12,13}$)) |(^(4936)(\d{12}$|\d{14,15}$)) |(^(564182)(\d{11}$|\d{13,14}$)) |(^(6333)[0-4](\d{11}$|\d{13,14}$)) |(^(6759)(\d{12}$|\d{14,15}$))
DescriptionSwitch Credit Card match. International safe.
Matches4903020000000008
Non-Matches4111111111111111
 
TitleJCB credit card
Expression(^(352)[8-9](\d{11}$|\d{12}$))|(^(35)[3-8](\d{12}$|\d{13}$))
DescriptionJCB Credit Card match. International safe.
Matches3528000000000007
Non-Matches4508750000000009
 
TitleDinner credit card
Expression(^(30)[0-5]\d{11}$)|(^(36)\d{12}$)|(^(38[0-8])\d{11}$)
DescriptionDiners Credit Card match. International safe.
Matches30000000000004
Non-Matches3528000000000007
 
TitleCart Blanche Credit Card
Expression^(389)[0-9]{11}$
DescriptionCart Blanche Credit Card match. International safe.
Matches38900000000007
Non-Matches30000000000004
 
TitleEnRoute Credit Card
Expression(^(2014)|^(2149))\d{11}$
DescriptionEnRoute Credit Card match. international safe.
Matches201400000000009
Non-Matches38900000000007
 
TitleUK Debit Cards
Expression(^(5[0678])\d{11,18}$)|(^(6[^05])\d{11,18}$)|(^(601)[^1]\d{9,16}$)|(^(6011)\d{9,11}$)|(^(6011)\d{13,16}$)|(^(65)\d{11,13}$)|(^(65)\d{15,18}$)|(^(49030)[2-9](\d{10}$|\d{12,13}$))|(^(49033)[5-9](\d{10}$|\d{12,13}$))|(^(49110)[1-2](\d{10}$|\d{12,13}$))|(^(49117)[4-9](\d{10}$|\d{12,13}$))|(^(49118)[0-2](\d{10}$|\d{12,13}$))|(^(4936)(\d{12}$|\d{14,15}$))
DescriptionMatches any of Solo, Switch, or Maestro. International safe. Will not match on Discover, Visa or Mastercard. For example; Most recommendations for matching Visa are that they start with “4”. If outside the US, these are incomplete on will falsely ID most Switch cards as Visa.
Matches6334500000000003
Non-Matches6011000000000004

Find more JavaScript tutorials, code snippets and samples here.

on in JavaScript DOM | Last modified on

Related Posts