npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@duffel/react-native-components-card-form

v1.0.0

Published

PCI-compliant React Native component to support card input and 3DS with the Duffel API

Readme

@duffel/react-native-components-card-form

PCI-compliant React Native components for collecting card details, saving cards, using saved cards, and completing 3DS authentication with the Duffel API.

This package is intended for apps integrating card passthrough for taking payments on the Duffel API. It handles the mobile UI and client-side calls that need to happen from the card form. You still need a backend that talks to the Duffel API and returns a clientKey to your app.

Installation

yarn add @duffel/react-native-components-card-form \
  @duffel/api \
  @evervault/react-native \
  @react-native-picker/picker \
  react-native-mask-input \
  react-native-picker-select \
  react-native-svg \
  react-native-webview

For iOS, install pods after adding the package:

cd ios && pod install

Before You Start

Create a Duffel client key on your backend and pass it to your app. Do not ship your Duffel API access token in your React Native app.

Your backend should:

  1. Authenticate the app user.
  2. Create or retrieve the Duffel resource the user is paying for.
  3. Generate a Duffel client key for the mobile session.
  4. Return the client key to the app.

Collect Card Details

Use DuffelCardForm to render the card form, then trigger the relevant action from your own button. The form calls onValidateSuccess whenever the current details are valid, and onValidateFailure if they become invalid again.

import React from 'react';
import { Button, View } from 'react-native';
import {
  DuffelCardForm,
  useDuffelCardFormActions,
} from '@duffel/react-native-components-card-form';

export function CheckoutCardForm({ clientKey }: { clientKey: string }) {
  const { ref, createCardForTemporaryUse } = useDuffelCardFormActions();
  const [canPay, setCanPay] = React.useState(false);

  return (
    <View>
      <DuffelCardForm
        ref={ref}
        clientKey={clientKey}
        intent="to-create-card-for-temporary-use"
        onValidateSuccess={() => setCanPay(true)}
        onValidateFailure={() => setCanPay(false)}
        onCreateCardForTemporaryUseSuccess={(card) => {
          // Send card.id to your backend to create the payment or order.
          console.log('Created card', card.id);
        }}
        onCreateCardForTemporaryUseFailure={(error) => {
          console.error('Could not create card', error);
        }}
      />

      <Button
        title="Pay"
        disabled={!canPay}
        onPress={createCardForTemporaryUse}
      />
    </View>
  );
}

Card Form Intents

Choose the intent that matches your checkout flow:

  • to-create-card-for-temporary-use: renders the full card form including CVC. Use this when the customer is paying with a new card. The returned card can be used for the current payment.
  • to-use-saved-card: renders only the CVC field for an existing saved card. Provide savedCardData={{ id, brand }} and call createCardForTemporaryUse.
  • to-save-card: renders the full card form without CVC. Use this when the customer is saving a card for later. Call saveCard.

Save a Card for Later

const { ref, saveCard } = useDuffelCardFormActions();

<DuffelCardForm
  ref={ref}
  clientKey={clientKey}
  intent="to-save-card"
  onValidateSuccess={() => setCanSave(true)}
  onValidateFailure={() => setCanSave(false)}
  onSaveCardSuccess={(card) => {
    console.log('Saved card', card.id);
  }}
  onSaveCardFailure={console.error}
/>;

<Button title="Save card" disabled={!canSave} onPress={saveCard} />;

Use a Saved Card

const { ref, createCardForTemporaryUse } = useDuffelCardFormActions();

<DuffelCardForm
  ref={ref}
  clientKey={clientKey}
  intent="to-use-saved-card"
  savedCardData={{ id: 'card_0000', brand: 'visa' }}
  onValidateSuccess={() => setCanPay(true)}
  onValidateFailure={() => setCanPay(false)}
  onCreateCardForTemporaryUseSuccess={(card) => {
    console.log('Card ready for payment', card.id);
  }}
  onCreateCardForTemporaryUseFailure={console.error}
/>;

3DS Authentication

Wrap your checkout screen with DuffelThreeDSecureProvider, then call create3DSecureSession before completing the payment on your backend.

Learn more in Duffel's card form component with 3DSecure guide.

import {
  DuffelThreeDSecureProvider,
  useCreate3DSecureSession,
} from '@duffel/react-native-components-card-form';

function CheckoutScreen({ clientKey }: { clientKey: string }) {
  return (
    <DuffelThreeDSecureProvider clientKey={clientKey}>
      <CheckoutContent />
    </DuffelThreeDSecureProvider>
  );
}

function CheckoutContent() {
  const { create3DSecureSession } = useCreate3DSecureSession();

  async function authenticateCard(cardId: string, offerId: string) {
    await create3DSecureSession(
      {
        card_id: cardId,
        resource_id: offerId,
        exception: null,
      },
      {
        onSuccess: (session) => {
          // Send session.id to your backend and complete the payment/order.
          console.log('3DS ready for payment', session.id);
        },
        onFailure: (error) => {
          // Authentication failed or was cancelled by the user.
          console.error(error);
        },
        onError: (error) => {
          // The session could not be created or the challenge could not render.
          console.error(error);
        },
      }
    );
  }
}

If Duffel returns a 3DS session that is already ready_for_payment, the success callback is called without showing a challenge.

Styling

Pass styles to customise the rendered fields:

<DuffelCardForm
  clientKey={clientKey}
  intent="to-create-card-for-temporary-use"
  styles={{
    input: { color: '#111827', fontSize: 16 },
    label: { color: '#374151', fontWeight: '600' },
    errorMessage: { color: '#B42318' },
    formField: { marginBottom: 16 },
    formContainer: { gap: 12 },
    sectionTitle: { fontSize: 18, fontWeight: '700' },
  }}
  onValidateSuccess={() => {}}
  onValidateFailure={() => {}}
  onCreateCardForTemporaryUseSuccess={() => {}}
  onCreateCardForTemporaryUseFailure={() => {}}
/>

The countryPicker style uses react-native-picker-select's PickerStyle type.

Custom Strings

Use customStrings to replace labels, placeholders, section titles, and validation messages:

<DuffelCardForm
  clientKey={clientKey}
  intent="to-create-card-for-temporary-use"
  customStrings={{
    cardNumberLabel: 'Card number',
    expirationDatePlaceholder: 'MM/YY',
    billingAddressSectionTitle: 'Billing address',
    cvvRequiredMessage: 'Enter the card security code',
  }}
  onValidateSuccess={() => {}}
  onValidateFailure={() => {}}
  onCreateCardForTemporaryUseSuccess={() => {}}
  onCreateCardForTemporaryUseFailure={() => {}}
/>

See DuffelCardFormStrings in the package types for the full list of strings.

API Reference

DuffelCardForm

Required props:

  • clientKey: Duffel client key returned by your backend.
  • intent: one of to-create-card-for-temporary-use, to-use-saved-card, or to-save-card.
  • onValidateSuccess: called when the current form data is valid.
  • onValidateFailure: called when the current form data is invalid.

Intent-specific props:

  • onCreateCardForTemporaryUseSuccess and onCreateCardForTemporaryUseFailure are required for to-create-card-for-temporary-use and to-use-saved-card.
  • savedCardData is required for to-use-saved-card.
  • onSaveCardSuccess and onSaveCardFailure are required for to-save-card.

Optional props:

  • styles: custom styles for inputs, labels, errors, and layout.
  • customStrings: replacement text for labels, placeholders, and validation messages.

useDuffelCardFormActions

Returns:

  • ref: pass this to DuffelCardForm.
  • createCardForTemporaryUse(): creates a card for the current payment. Use with to-create-card-for-temporary-use or to-use-saved-card.
  • saveCard(): saves a card for later. Use with to-save-card.

DuffelThreeDSecureProvider

Props:

  • clientKey: Duffel client key returned by your backend.
  • children: checkout UI that needs access to 3DS.

useCreate3DSecureSession

Returns create3DSecureSession(payload, callbacks).

Payload:

  • card_id: card ID returned by the card form.
  • resource_id: Duffel resource ID for the payment, such as an offer or order.
  • exception: secure_corporate_payment or null.
  • services: optional service IDs and quantities for ancillary payments.

Callbacks:

  • onSuccess(session): 3DS is ready for payment. Complete the payment on your backend.
  • onFailure(error): authentication failed or was cancelled.
  • onError(error): the session could not be created or the challenge could not render.