Powered by Coinflow
Payments · Documentation
Operational

Card Form Components

Use Coinflow’s Card Form SDK components to securely collect and tokenize credit card information with a single tokenize() call. Available for React, Vue, Angular, and React Native.

Coinflow’s Card Form components provide a streamlined, PCI-compliant way to collect credit card information directly in your application. Instead of managing separate card number, CVV, and expiration inputs, these components bundle everything into a single embeddable form with one tokenize() method.

When to Use Card Form Components

Use these components when you want to:

  • Collect card details for a new card checkout without building your own form layout
  • Tokenize a card number with expiration for use with the Card Checkout API
  • Re-collect a CVV only for a saved card before calling the Saved Card Checkout API
  • Apply custom theming (fonts, colors, placeholders) to match your brand

Available Components

Component Description
CoinflowCardForm Full card input — card number, expiration date, and CVV. Renders in a single row on wide containers and automatically reflows to two rows when space is constrained
CoinflowCardNumberForm Card number and expiration date only (no CVV)
CoinflowCvvForm CVV-only input for re-tokenizing a saved card

All three components expose a tokenize() method via a ref that returns a token you can pass to the Coinflow checkout APIs.

Installation

npm

npm install @coinflowlabs/react

Vue

npm install @coinflowlabs/vue

Angular

npm install @coinflowlabs/angular

React Native

npm install @coinflowlabs/react-native

Tokenizing a New Card

Use CoinflowCardForm to collect the full card details (number, expiration, CVV) and tokenize them in a single call.

React

import {useRef} from 'react';
import {
  CoinflowCardForm,
  CardFormRef,
  CoinflowEnvs,
} from '@coinflowlabs/react';

function NewCardCheckout() {
  const cardFormRef = useRef<CardFormRef>(null);

  const handleTokenize = async () => {
    try {
      const result = await cardFormRef.current?.tokenize();
      if (!result) return;

      console.log('Token:', result.token);
      console.log('Exp Month:', result.expMonth);
      console.log('Exp Year:', result.expYear);

      // Pass result.token, result.expMonth, result.expYear
      // to the Card Checkout API endpoint
    } catch (err) {
      console.error('Tokenization failed:', err);
    }
  };

  return (
    <div>
      <CoinflowCardForm
        ref={cardFormRef}
        merchantId="your-merchant-id"
        env="sandbox"
      />
      <button onClick={handleTokenize}>Pay</button>
    </div>
  );
}

Vue

<script setup lang="ts">
import {ref} from 'vue';
import {CoinflowCardForm} from '@coinflowlabs/vue';

const cardFormRef = ref<InstanceType<typeof CoinflowCardForm> | null>(null);

async function handleTokenize() {
  try {
    const result = await cardFormRef.value?.tokenize();
    if (!result) return;

    console.log('Token:', result.token);
    console.log('Exp Month:', result.expMonth);
    console.log('Exp Year:', result.expYear);

    // Pass result.token, result.expMonth, result.expYear
    // to the Card Checkout API endpoint
  } catch (err) {
    console.error('Tokenization failed:', err);
  }
}
</script>

<template>
  <div>
    <CoinflowCardForm
      ref="cardFormRef"
      :args="{
        merchantId: 'your-merchant-id',
        env: 'sandbox',
        variant: 'card-form',
      }"
    />
    <button @click="handleTokenize">Pay</button>
  </div>
</template>

Angular

import {Component, ViewChild} from '@angular/core';
import {CoinflowCardForm} from '@coinflowlabs/angular';

@Component({
  selector: 'app-checkout',
  standalone: true,
  imports: [CoinflowCardForm],
  template: `
    <lib-coinflow-card-form
      #cardForm
      [args]="{
        merchantId: 'your-merchant-id',
        env: 'sandbox',
        variant: 'card-form'
      }"
    />
    <button (click)="handleTokenize()">Pay</button>
  `,
})
export class CheckoutComponent {
  @ViewChild('cardForm') cardForm!: CoinflowCardForm;

  async handleTokenize() {
    try {
      const result = await this.cardForm.tokenize();
      console.log('Token:', result.token);
      console.log('Exp Month:', result.expMonth);
      console.log('Exp Year:', result.expYear);

      // Pass result.token, result.expMonth, result.expYear
      // to the Card Checkout API endpoint
    } catch (err) {
      console.error('Tokenization failed:', err);
    }
  }
}

React Native

import {useRef} from 'react';
import {Button, View} from 'react-native';
import {
  CoinflowCardForm,
  CardFormNativeRef,
} from '@coinflowlabs/react-native';

function NewCardCheckout() {
  const cardFormRef = useRef<CardFormNativeRef>(null);

  const handleTokenize = async () => {
    try {
      const result = await cardFormRef.current?.tokenize();
      if (!result) return;

      console.log('Token:', result.token);
      console.log('Exp Month:', result.expMonth);
      console.log('Exp Year:', result.expYear);
    } catch (err) {
      console.error('Tokenization failed:', err);
    }
  };

  return (
    <View>
      <CoinflowCardForm
        ref={cardFormRef}
        merchantId="your-merchant-id"
        env="sandbox"
      />
      <Button title="Pay" onPress={handleTokenize} />
    </View>
  );
}

Refreshing a Saved Card Token (CVV Only)

When a customer pays with a saved card, you need to re-collect the CVV and refresh the token. Use CoinflowCvvForm with the saved card’s token from the Get Customer endpoint.

React

import {useRef} from 'react';
import {CoinflowCvvForm, CardFormRef} from '@coinflowlabs/react';

function SavedCardCheckout({savedCardToken}: {savedCardToken: string}) {
  const cvvFormRef = useRef<CardFormRef>(null);

  const handleTokenize = async () => {
    try {
      const result = await cvvFormRef.current?.tokenize();
      if (!result) return;

      // Pass result.token to the Saved Card Checkout API endpoint
      console.log('Refreshed token:', result.token);
    } catch (err) {
      console.error('CVV tokenization failed:', err);
    }
  };

  return (
    <div>
      <CoinflowCvvForm
        ref={cvvFormRef}
        merchantId="your-merchant-id"
        env="sandbox"
        token={savedCardToken}
      />
      <button onClick={handleTokenize}>Pay with Saved Card</button>
    </div>
  );
}

Vue

<script setup lang="ts">
import {ref} from 'vue';
import {CoinflowCardForm} from '@coinflowlabs/vue';

const props = defineProps<{savedCardToken: string}>();
const cvvFormRef = ref<InstanceType<typeof CoinflowCardForm> | null>(null);

async function handleTokenize() {
  try {
    const result = await cvvFormRef.value?.tokenize();
    if (!result) return;

    console.log('Refreshed token:', result.token);
  } catch (err) {
    console.error('CVV tokenization failed:', err);
  }
}
</script>

<template>
  <div>
    <CoinflowCardForm
      ref="cvvFormRef"
      :args="{
        merchantId: 'your-merchant-id',
        env: 'sandbox',
        variant: 'cvv-form',
        token: props.savedCardToken,
      }"
    />
    <button @click="handleTokenize">Pay with Saved Card</button>
  </div>
</template>

In Vue, the CoinflowCardForm component accepts a variant prop to switch between 'card-form', 'card-number-form', and 'cvv-form' modes.

Tokenizing Card Number Only (No CVV)

Use CoinflowCardNumberForm when you only need to collect the card number and expiration — for example, when saving a card for future use without an immediate charge.

import {useRef} from 'react';
import {CoinflowCardNumberForm, CardFormRef} from '@coinflowlabs/react';

function SaveCardForLater() {
  const cardNumberRef = useRef<CardFormRef>(null);

  const handleTokenize = async () => {
    const result = await cardNumberRef.current?.tokenize();
    if (!result) return;

    // Store result.token, result.expMonth, result.expYear for later use
    console.log('Token:', result.token);
  };

  return (
    <div>
      <CoinflowCardNumberForm
        ref={cardNumberRef}
        merchantId="your-merchant-id"
        env="sandbox"
      />
      <button onClick={handleTokenize}>Save Card</button>
    </div>
  );
}

tokenize() Response

The tokenize() method returns a CardFormTokenResponse:

Field Type Description
token string The PCI-compliant card token to pass to checkout APIs
expMonth string (optional) Two-digit expiration month (e.g., "05") — returned by CoinflowCardForm and CoinflowCardNumberForm
expYear string (optional) Two-digit expiration year (e.g., "30") — returned by CoinflowCardForm and CoinflowCardNumberForm

CoinflowCvvForm only returns token since expiration details are already stored with the saved card.

Theming

All card form components accept a theme prop to customize the look and feel. Theme values are passed as a MerchantTheme object.

Property Type Description
font string Font family name — any Google Font is supported (e.g., "Inter", "Red Hat Display")
fontSize string Font size for input text (e.g., "12px", "14px")
background string Background color for input fields (e.g., "#ffffff", "#1a1a1a")
textColor string Input text color
style MerchantStyle Border radius style — MerchantStyle.Rounded, MerchantStyle.Pill, or MerchantStyle.Sharp
showCardIcon boolean Show the detected card brand icon (Visa, Mastercard, etc.) to the left of the card number input
cardNumberPlaceholder string Placeholder for the card number field
cvvPlaceholder string Placeholder for the CVV field
expirationPlaceholder string Placeholder for month/year fields (format: "MM / YY")
<CoinflowCardForm
  ref={cardFormRef}
  merchantId="your-merchant-id"
  env="sandbox"
  theme={{
    font: 'Inter',
    fontSize: '14px',
    background: '#ffffff',
    textColor: '#111827',
    style: MerchantStyle.Rounded,
    showCardIcon: true,
    cardNumberPlaceholder: 'Card number',
    cvvPlaceholder: 'CVV',
    expirationPlaceholder: 'MM / YY',
  }}
/>

The theme values shown above are examples for illustration. Configure your branding in the Merchant Dashboard or contact the Coinflow integrations team to set these values for your account.

Responsive Layout

CoinflowCardForm automatically adapts its layout to the width of the container you place it in — no configuration is required.

  • Wide containers — the card number, expiration, and CVV render together on a single row.
  • Narrow containers — when there isn’t enough horizontal space for all three fields, the form reflows to two rows: the card number on the first row, with the expiration and CVV on the second.

This is especially useful in mobile checkout UIs, where a single-row layout can clip the card number in narrow viewports. The form measures its own container and switches layouts on the fly, including when the viewport is resized or rotated.

Because the form’s height changes when it reflows, the embedded iframe reports its content height back to the SDK, which resizes the iframe automatically so the fields are never clipped.

To let the form size itself correctly, place it in a container whose width you control and whose height is allowed to grow. Avoid setting a fixed height on the component or its wrapping element — doing so prevents the form from expanding to its two-row layout.

Responsive reflow and automatic height adjustment are built in to CoinflowCardForm. To pick up this behavior, update to the latest version of your SDK (@coinflowlabs/react, @coinflowlabs/vue, @coinflowlabs/angular, or @coinflowlabs/react-native). No code changes are needed.

Component Props Reference

CoinflowCardForm / CoinflowCardNumberForm

Prop Type Required Description
merchantId string Yes Your Coinflow merchant ID
env CoinflowEnvs No "sandbox" or "prod" (defaults to "prod")
theme MerchantTheme No Custom theming options
onLoad () => void No Callback when the form iframe has loaded

CoinflowCvvForm

Prop Type Required Description
merchantId string Yes Your Coinflow merchant ID
env CoinflowEnvs No "sandbox" or "prod" (defaults to "prod")
theme MerchantTheme No Custom theming options
token string Yes The saved card token from Get Customer
onLoad () => void No Callback when the form iframe has loaded

Token Expiration

Tokens expire if not used within 7 days of creation. Once used, a token is valid for 5 minutes in production. In the sandbox environment, tokens remain valid indefinitely. If a token expires, call tokenize() again to generate a new one.

Migrating from Legacy Card Inputs

If you are currently using CoinflowCardNumberInput and CoinflowCvvInput, the new Card Form components simplify your integration:

Legacy New
CoinflowCardNumberInput + CoinflowCvvInput + manual expiration input CoinflowCardForm (all-in-one)
CoinflowCardNumberInput + manual expiration input CoinflowCardNumberForm
CoinflowCvvOnlyInput CoinflowCvvForm
ref.current.getToken() ref.current.tokenize()
CSS string-based styling (css prop) Object-based theming (theme prop)

The legacy components continue to work but are deprecated. New integrations should use the Card Form components.