React Bindings

Providers, field components and hooks that mount the Wirex card frames and handle their lifecycle for you.

Before You Start

Read the following guides before proceeding:

GuideWhy
PCI Compliant SDKIsolation model and package map
SDK SetupClient id, environments, installation, CSP
Collect a Top-Up CardTokenize parameters and results
Events and Error HandlingFailure modes shared with the vanilla packages

Overview

@wirexapp/card-react is the first-party React binding: providers and field components for card
collection, and self-contained components for reveal and 3DS. It offers the same guarantees as the vanilla
packages — card data exists only inside Wirex-served iframes — with mounting and teardown handled for you.

npm install @wirexapp/card-react

react >= 18 is a peer dependency. Every component is client-only; 'use client' is compiled in, so in
the Next.js App Router they work inside your client components with no extra directive.

For frameworks other than React, integrate the vanilla packages directly. The binding adds convenience, not
capability.


Top-Up Collection

import {
  CardTopUpProvider,
  CardNumberField,
  CardExpiryField,
  CardCvvField,
  CardholderNameField,
  useCardTopUp,
} from '@wirexapp/card-react';

const sdk = { environment: 'uat', clientId: 'a4f6c1e2-9b03-4d77-8a51-2f0c6b8e4d19' };

export function AddCardScreen() {
  return (
    <CardTopUpProvider
      sdk={sdk}
      auth={{ getBearerToken: () => session.getAccessToken() }}
      appearance={{ theme: 'dark' }}
    >
      <CardNumberField />
      <div className="row">
        <CardExpiryField />
        <CardCvvField />
      </div>
      <CardholderNameField />
      <SubmitButton />
    </CardTopUpProvider>
  );
}

function SubmitButton() {
  const { ready, state, tokenizeTopUp } = useCardTopUp();

  const submit = async () => {
    const { cardId } = await tokenizeTopUp({ billingDetails: getBillingAddress() });
    // Continue with estimate, execute and 3DS.
  };

  return (
    <button disabled={!ready || !state?.complete} onClick={submit}>
      Continue
    </button>
  );
}

Provider Props

PropTypeRequiredDescription
sdkobjectYes{ environment?, clientId? } — the same config the vanilla creators take
authobjectYes{ getBearerToken } — returns a fresh user token
appearanceobjectNoWhitelisted styling tokens — see Appearance and Localization
stringsobjectNoTranslated labels and validation messages
onChange(state) => voidNoAggregated validity and detected brand
onReady() => voidNoFires once, when every field of the profile has mounted
onMountError(error) => voidNoA field iframe failed to load or initialize
childrennodeYesField components and your own layout

useCardTopUp()

ValueTypeDescription
readybooleantrue once all four fields have mounted
stateobject | nullLatest { complete, brand, fields } snapshot. null before the first change event
tokenizeTopUpfunctionSame parameters and result as the vanilla tokenizer

Field Components

ComponentField
CardNumberFieldnumber
CardExpiryFieldexpiry
CardCvvFieldcvv
CardholderNameFieldname

Each renders one iframe and accepts className and style for its container only. The field's own
appearance comes from the provider's appearance tokens, not from your CSS. Place them anywhere inside the
provider, in any layout.


Payout Collection

The same model with the card-number field only. Recipient name and labels are non-sensitive — collect them
with your own inputs.

import { OctDestinationProvider, CardNumberField, useOctDestination } from '@wirexapp/card-react';

<OctDestinationProvider sdk={sdk} auth={auth}>
  <CardNumberField />
  {/* your own inputs for cardholder name, label, third-party flag */}
  <SendButton />
</OctDestinationProvider>;

// Inside SendButton:
const { ready, tokenizeOctDestination } = useOctDestination();
const { externalCardId, last4 } = await tokenizeOctDestination({
  cardholderName,
  cardLabel,
  isSaved: true,
  isThirdParty: true,
});

OctDestinationProvider takes the same props as CardTopUpProvider. useOctDestination() returns
{ ready, state, tokenizeOctDestination }. Rendering CardExpiryField, CardCvvField or
CardholderNameField under it throws — those fields are not part of the oct-destination profile.


Reveal

import { CardReveal } from '@wirexapp/card-react';

<CardReveal
  sdk={sdk}
  cardId={card.id}
  actionToken={actionToken}
  fetchDetails
  fetchCvv
  fields={['cardholder', 'number', 'expiry', 'cvv']}
  cardholderName=USER.DISPLAYNAME
  auth={{
    getBearerToken: () => session.getAccessToken(),
    userEmail: user.email,
    userWallet: user.walletAddress,
  }}
  onStateChange={({ status, errorMessage }) => status === 'error' && toast.error(errorMessage)}
/>;

Props mirror the vanilla config plus sdk, className, style
and onMountError. The component remounts — and refetches — when cardId or actionToken change. A fresh
token is a fresh reveal.


3DS Challenge

import { ThreeDsChallenge } from '@wirexapp/card-react';

<ThreeDsChallenge
  url={execute.three_ds_state.url}
  onComplete={status => finishTopUp(status)}
  onError={() => finishTopUp('Failed')}
  style={{ height: 480, background: '#fff', borderRadius: 8 }}
/>;

Props mirror the vanilla config plus className and style.
Give the container real dimensions — issuer pages assume 500×480 pixels or larger and a light background.
Render your own cancel control and unmount the component; treat a user-cancelled challenge as Pending,
not Failed.


Re-Render Rules

The collect group is recreated only when one of these changes:

InputEffect on the frames
sdk.environment, sdk.clientId, sdk.frameOrigin, sdk.framePathThe group is destroyed and recreated. The user's input is lost
Provider profile — swapping CardTopUpProvider for OctDestinationProviderThe group is destroyed and recreated
auth, appearance, strings, onChange, onReady, onMountError identityNo remount. The latest value is used at the next call

The comparison is on the values inside sdk, not on the object's identity, so an inline sdk={{ … }}
literal does not remount on every render. Passing a new appearance object does not re-theme a mounted
frame — appearance is read at mount.

Every component is safe under React 18 StrictMode. Fields mount, unmount and remount without leaking
iframes or message listeners.


Exports

ExportKind
CardTopUpProvider, useCardTopUpTop-up collect context and hook
OctDestinationProvider, useOctDestinationPayout collect context and hook
CardNumberField, CardExpiryField, CardCvvField, CardholderNameFieldField components
CardRevealOwn-card reveal element
ThreeDsChallenge3DS step-up element
PciFrameRequestErrorError class, re-exported for instanceof checks

All shared types — PciAppearance, PciCollectChangeState, PciRevealElementConfig, PciRevealAuth,
tokenize parameter and result types — are re-exported from this package, so a React integration needs no
direct dependency on the vanilla packages.


Did this page help you?