Card Payment Input
A specialized input component for credit/debit card numbers. Features automatic card brand detection, number formatting with spaces, and Luhn validation. Supports all major card brands including Visa, Mastercard, American Express, Discover, Diners Club, JCB, and UnionPay.
Basic Usage
import { CardPaymentInput } from '@/components'
<CardPaymentInput placeholder="0000 0000 0000 0000" />With Label and Hint
Add a label and helper text to guide users.
<CardPaymentInput
label="Card number"
hint="Enter your card number"
required
/>Enter your card number
Sizes
The input comes in three sizes: small (36px), medium (40px, default), and large (44px).
Small (36px)
Medium (40px) - Default
Large (44px)
Small
<CardPaymentInput size="sm" label="Card number" />Medium (Default)
<CardPaymentInput size="md" label="Card number" />Large
<CardPaymentInput size="lg" label="Card number" />Card Brand Detection
The component automatically detects the card brand as the user types and displays the appropriate icon. It supports:
- Visa - starts with 4
- Mastercard - starts with 51-55 or 2221-2720
- American Express - starts with 34 or 37
- Discover - starts with 6011, 644-649, or 65
- Diners Club - starts with 300-305, 36, or 38
- JCB - starts with 3528-3589
- UnionPay - starts with 62
Visa (starts with 4)
Mastercard (starts with 51-55)
American Express (starts with 34/37)
Discover (starts with 6011/65)
Diners Club (starts with 36)
JCB (starts with 35)
Card Number Formatting
The input automatically formats card numbers with spaces:
- Standard cards (Visa, Mastercard, etc.):
0000 0000 0000 0000(4-4-4-4) - American Express:
0000 000000 00000(4-6-5) - Diners Club:
0000 000000 0000(4-6-4)
Default (empty)
Filled (Visa)
Filled (Mastercard)
Filled (Amex)
Required Fields
Use the required prop to show a required indicator (blue asterisk).
<CardPaymentInput
label="Card number"
hint="This field is required"
required
/>This field is required
Optional Fields
Use showOptionalBadge to indicate optional fields.
<CardPaymentInput
label="Card number"
showOptionalBadge
/>Error State
Show validation errors with the error prop. Pass a string to display an error message, or true for styling only.
Error with message
Please enter a valid card number
Error styling only
This card number is invalid
Error with Message
<CardPaymentInput
label="Card number"
error="Please enter a valid card number"
/>Error Styling Only
<CardPaymentInput
label="Card number"
error
hint="This card number is invalid"
/>Disabled State
Disabled inputs cannot be interacted with.
<CardPaymentInput
label="Card number"
defaultValue="4111111111111111"
disabled
/>Icon Customization
Control the visibility of the left credit card icon and the right brand icon.
Without left icon
Without brand icon
Without any icons
Without Left Icon
<CardPaymentInput label="Card number" showLeftIcon={false} />Without Brand Icon
<CardPaymentInput label="Card number" showBrandIcon={false} />Controlled Input
Control the input value externally with real-time validation feedback. The onChange callback provides detailed card information including the raw value, formatted value, detected brand, and validation status.
const [value, setValue] = useState('')
const [cardInfo, setCardInfo] = useState<CardInfo | null>(null)
<CardPaymentInput
label="Card number"
value={value}
onChange={(rawValue, info) => {
setValue(rawValue)
setCardInfo(info)
}}
error={cardInfo && !cardInfo.isPotentiallyValid}
hint={cardInfo?.isValid ? 'Card number is valid!' : 'Enter a valid card number'}
required
/>
// cardInfo contains:
// - rawValue: '4111111111111111'
// - formattedValue: '4111 1111 1111 1111'
// - cardBrand: 'visa'
// - isValid: true (passes Luhn check and correct length)
// - isPotentiallyValid: true (could become valid with more input)Enter a valid card number
(empty)(empty)unknownValidation
The component includes built-in Luhn algorithm validation. The onChange callback provides:
isValid-truewhen the card number passes the Luhn check AND has a valid length for the detected card typeisPotentiallyValid-truewhen the number could become valid with more input
<CardPaymentInput
onChange={(value, cardInfo) => {
if (cardInfo.isValid) {
console.log('Valid card:', cardInfo.cardBrand)
}
}}
/>All States Overview
Default States
Empty
Filled (Visa)
Error
Invalid card number
Disabled
Size Variants
Small
Medium
Large
Card Brands
Visa
Mastercard
Amex
Discover
Accessibility
- Uses
inputMode="numeric"for mobile number pad - Uses
autoComplete="cc-number"for browser autofill - Labels are properly associated with inputs via
htmlFor/id aria-describedbyconnects hint/error text to the inputaria-invalidis set when in error statearia-requiredis set for required fields- Focus states are clearly visible
- Full keyboard navigation support
API Reference
CardPaymentInput Props
| Prop | Type | Default | Description |
|---|---|---|---|
| label | string | - | Label text above the input |
| hint | string | - | Helper text below the input |
| error | boolean | string | false | Error state or error message |
| size | 'sm' | 'md' | 'lg' | 'md' | Input size variant |
| value | string | - | Controlled value (digits only) |
| defaultValue | string | '' | Initial value for uncontrolled usage |
| onChange | (value: string, cardInfo: CardInfo) => void | - | Callback when value changes |
| onCardBrandChange | (brand: CardBrand) => void | - | Callback when card brand changes |
| showLeftIcon | boolean | true | Show credit card icon on left |
| showBrandIcon | boolean | true | Show detected brand icon on right |
| showOptionalBadge | boolean | false | Show "(Optional)" badge |
| showInfoIcon | boolean | false | Show info icon in label |
| disabled | boolean | false | Disable the input |
| required | boolean | false | Mark as required |
All standard HTML input attributes (except type and onChange) are also supported.
CardInfo Type
The CardInfo object returned from onChange:
| Property | Type | Description |
|---|---|---|
| rawValue | string | Card number with digits only |
| formattedValue | string | Card number with spaces |
| cardBrand | CardBrand | Detected card brand |
| isValid | boolean | Passes Luhn check and valid length |
| isPotentiallyValid | boolean | Could become valid with more input |
CardBrand Type
type CardBrand =
| 'visa'
| 'mastercard'
| 'amex'
| 'discover'
| 'diners'
| 'jcb'
| 'unionpay'
| 'unknown'