Why This Question Is Important
This is not a UI question. It is a system design question at component level. Interviewers are checking whether you can handle real-world complexity inside a single input field. A strong solution shows control over formatting, validation, UX, and edge cases — all in real-time.
What You Must Build (Interview Requirements)
- Auto format card number (spaces, grouping)
- Detect card type dynamically
- Validate using Luhn algorithm
- Support multiple card types (Visa, MasterCard, Amex, RuPay, etc.)
- Handle expiry (MM/YY) with validation
- Handle CVV with dynamic length (3/4 digits)
- Mask card number (optional)
- Handle paste, delete, cursor position
- Provide real-time feedback
Final Expected UI
Card Number: 4242 4242 4242 4242
Card Type: VISA
Expiry: 12/28
CVV: 123
Status: Valid ✅Step 1: Understanding Card Types (Very Important)
Different cards have different patterns, lengths, and formatting rules. A good implementation supports these differences.
const CARD_CONFIG = [
{ type: "VISA", prefix: /^4/, lengths: [13, 16, 19], cvv: 3 },
{ type: "MASTERCARD", prefix: /^5[1-5]/, lengths: [16], cvv: 3 },
{ type: "AMEX", prefix: /^3[47]/, lengths: [15], cvv: 4 },
{ type: "RUPAY", prefix: /^6/, lengths: [16], cvv: 3 },
];Example: Amex uses 15 digits and 4-digit CVV, while Visa uses 16 digits and 3-digit CVV.
Step 2: Detect Card Type
const detectCardType = (number: string) => {
return CARD_CONFIG.find((card) =>
card.prefix.test(number)
)?.type || "UNKNOWN";
};This runs on every keystroke and allows dynamic UI updates like logos or CVV length.
Step 3: Smart Formatting (Not Always 4-4-4-4)
Not all cards use same grouping. Amex uses 4-6-5 pattern.
const formatCardNumber = (value: string, type: string) => {
const clean = value.replace(/\D/g, "");
if (type === "AMEX") {
return clean
.replace(/(\d{4})(\d{6})(\d{0,5})/, "$1 $2 $3")
.trim();
}
return clean
.replace(/(.{4})/g, "$1 ")
.trim();
};Example: AMEX → 3782 822463 10005 VISA → 4242 4242 4242 4242
Step 4: Luhn Algorithm (Validation Core)
This algorithm ensures card number is mathematically valid.
const luhnCheck = (num: string) => {
let sum = 0;
let double = false;
for (let i = num.length - 1; i >= 0; i--) {
let digit = +num[i];
if (double) {
digit *= 2;
if (digit > 9) digit -= 9;
}
sum += digit;
double = !double;
}
return sum % 10 === 0;
};Without Luhn validation, your solution is considered incomplete in interviews.
Step 5: Expiry Input (MM/YY)
const formatExpiry = (value: string) => {
const clean = value.replace(/\D/g, "");
return clean.replace(/(\d{2})(\d{0,2})/, "$1/$2");
};Validation logic:
const validateExpiry = (value: string) => {
const [month, year] = value.split("/");
if (!month || !year) return false;
const m = parseInt(month);
const y = parseInt("20" + year);
if (m < 1 || m > 12) return false;
const now = new Date();
const expiry = new Date(y, m);
return expiry > now;
};Step 6: CVV Handling
CVV length depends on card type.
const validateCVV = (cvv: string, type: string) => {
const config = CARD_CONFIG.find(c => c.type === type);
return cvv.length === config?.cvv;
};Step 7: Full React Implementation
import { useState } from "react";
export default function CreditCard() {
const [card, setCard] = useState("");
const [expiry, setExpiry] = useState("");
const [cvv, setCvv] = useState("");
const raw = card.replace(/\s/g, "");
const type = detectCardType(raw);
const isValid = luhnCheck(raw);
return (
<div>
<input
placeholder="Card Number"
value={card}
onChange={(e) => {
const raw = e.target.value.replace(/\D/g, "");
const type = detectCardType(raw);
setCard(formatCardNumber(raw, type));
}}
/>
<p>Type: {type}</p>
<p>Valid: {isValid ? "Yes" : "No"}</p>
<input
placeholder="MM/YY"
value={expiry}
onChange={(e) =>
setExpiry(formatExpiry(e.target.value))
}
/>
<input
placeholder="CVV"
value={cvv}
onChange={(e) =>
setCvv(e.target.value.replace(/\D/g, ""))
}
/>
</div>
);
}Real User Flow (Important for Interview Explanation)
User types: 4
→ Detect VISA
User types: 4242
→ Format → 4242
User types full:
→ 4242 4242 4242 4242
→ Run Luhn
→ Show VALID
User enters expiry:
→ 12 → 12/
→ 12/28 → validatedEdge Cases You Must Handle
- User pastes full card number
- Deleting from middle
- Cursor jump issue after formatting
- Invalid characters
- Different card lengths
- Incomplete input states
Advanced (What Makes You Stand Out)
- Mask card → **** **** **** 4242
- Auto move to next field
- Show card logo dynamically
- Disable submit until valid
- Add error states (red border)
- Debounce validation
Final Takeaway
This problem tests real-world frontend engineering. A strong candidate not only formats input but builds a system that feels natural, responsive, and correct.
If you can explain card detection, Luhn validation, formatting logic, and edge cases clearly while writing clean code, you will easily clear this machine coding round.