crd-ui

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.

Why it breaks on React 18 and 19

react-credit-cards declares react@^15 || ^16 as a peer dependency, so on any newer React npm refuses to install it:

npm error code ERESOLVE
npm error ERESOLVE unable to resolve dependency tree
npm error
npm error Found: react@19.3.0
npm error Could not resolve dependency:
npm error peer react@"^15.0.0 || ^16.0.0" from react-credit-cards@0.8.3

--legacy-peer-deps silences the error but not the cause: it's a class component validated with propTypes, which React 19 no longer checks. crd-ui supports React 18 and 19 and ships its own TypeScript types.

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-cardscrd-uiNotes
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

See the full documentation →