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.

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 →