Migrating from react-credit-cards
react-credit-cards has not shipped a release since June 2020. Its fork, react-credit-cards-2, is maintained but exposes the same API — so this guide covers both.
The move is close to a drop-in. The four value props and
focused keep their names and their types, so most codebases only change
the import and the stylesheet.
The swap
Before:
import Cards from 'react-credit-cards';
import 'react-credit-cards/es/styles-compiled.css';
<Cards
number={number}
name={name}
expiry={expiry}
cvc={cvc}
focused={focused}
/>; After:
import { Card } from 'crd-ui/react';
import 'crd-ui/styles.css';
<Card
number={number}
name={name}
expiry={expiry}
cvc={cvc}
focused={focused}
/>; Every prop, mapped
| react-credit-cards | crd-ui | Notes |
|---|---|---|
number | number | Same name, same string. |
name | name | Same name, same string. |
expiry | expiry | Same name; normalized to MM/YY. |
cvc | cvc | Same name, same string. |
focused | focused | Same name and same values ('number' | 'name' | 'expiry' | 'cvc'). |
placeholders | placeholders | Same shape: { name }. |
locale | locale | Key renamed: { valid } becomes { validThru }. |
preview + issuer | layout="display" + brand + last4 | Also reveals real values on demand and can copy them on click. |
callback | onBrandChange | Partial — reports the brand only. See below. |
acceptedCards | — | No equivalent. Gate on the detected brand yourself. See below. |
$rccs-size (SCSS) | --crd-width (CSS var) | No stylesheet to recompile. |
$rccs-shadow | --crd-shadow | Same idea, as a custom property. |
$rccs-card-ratio | — | Fixed at the ISO/IEC 7810 ID-1 ratio. |
The two that aren't drop-in
callback(type, isValid) reported the brand, the max length and validity
in one go. onBrandChange gives you the brand; the rest comes from the
same helpers the library uses internally, so nothing is lost:
// callback(type, isValid) has no direct equal: onBrandChange
// reports the brand. Rebuild the rest from the exported helpers.
import { detectBrand, getBrandSpec } from 'crd-ui';
const onNumber = (value) => {
const brand = detectBrand(value);
if (!brand) return { brand: null, maxLength: 19, isValid: false };
const { lengths, maskLength } = getBrandSpec(brand); // maskLength counts digits
const digits = value.replace(/\D/g, '').length;
return { brand, maxLength: maskLength, isValid: lengths.includes(digits) };
}; acceptedCards has no equivalent — crd-ui always shows what it detects.
Deciding what you accept stays in your code, which also lets you word the rejection
yourself:
// acceptedCards has no equal either — gate on the detected
// brand yourself, which also lets you show your own message.
const ACCEPTED = ['visa', 'mastercard'];
<Card number={number} onBrandChange={(b) => setRejected(!!b && !ACCEPTED.includes(b))} />; Preview mode becomes a layout
preview plus issuer rendered a scrambled card. In crd-ui
that's layout="display", built for dashboards and saved-card lists:
// preview + issuer becomes the display layout, which also
// reveals real values on demand and can copy them on click.
<Card
layout="display"
brand="visa"
last4="4242"
copyable
/>; Theming without SCSS
The $rccs-* SCSS variables required compiling the stylesheet. crd-ui
exposes CSS custom properties instead, so you override them anywhere — including
from Tailwind utilities:
/* The SCSS variables become CSS custom properties, so there is
no stylesheet to recompile: $rccs-size -> --crd-width, and so on. */
.crd {
--crd-width: 290px;
--crd-shadow: 0 0 20px rgba(0, 0, 0, 0.2);
--crd-font: Consolas, Courier, monospace;
} What you gain
- It's maintained. That's the whole reason you're reading this.
- Zero runtime dependencies.
- Not just React. The same component ships for Vue, Svelte and vanilla JS from one package.
- TypeScript types in the box.
- A display layout for cards the user already owns, with click-to-reveal and click-to-copy.
- Six finishes, a 3D hover tilt, and 45 free card backgrounds.