@checkout.com/checkout-react-native-components
v1.0.0-beta8
Published
React Native wrapper for native iOS & Android Checkout components
Readme
Checkout React Native Components
- 🚀 Quick Start
- 🧩 Components Overview
- ⚙️ Core Configuration
- 📖 Component Reference
- 🔧 Advanced Features
- 🎨 Customization
- 📡 Event Handling
- 🔍 Linting & formatting
- 🪝 Git hooks (Lefthook)
- 📄 License
For detailed integration steps, refer to our official documentation ↗️ .
🚀 Quick Start
Installation
Install the package using your preferred package manager:
npm install @checkout.com/checkout-react-native-componentsyarn add @checkout.com/checkout-react-native-componentsPlatform Setup
This package supports both React Native architectures (New Architecture/Fabric and Old Architecture/Paper) out of the box.
📱 iOS Setup
cd ios
pod installDepending on which version of checkout-react-native-components you use, you may need to pin FingerprintPro to either 2.12.0 or above. You can do this by manually modifying your Podfile with the following:
pod 'FingerprintPro', '2.12.0'For expo, use the expo-build-properties plugin:
[
"expo-build-properties",
{
"ios": {
"extraPods": [
{
"name": "FingerprintPro",
"version": "2.12.0"
}
]
}
}
]🤖 Android Setup
Add the following repositories to your app's settings.gradle:
dependencyResolutionManagement {
repositoriesMode.set(RepositoriesMode.PREFER_SETTINGS)
repositories {
google()
mavenCentral()
maven { url = uri("https://jitpack.io") }
maven { url = uri("https://maven.fpregistry.io/releases") }
}
}Or add the allProjects block to the project build.gradle:
allprojects {
repositories {
google()
mavenCentral()
maven { url 'https://maven.fpregistry.io/releases' }
maven { url 'https://www.jitpack.io' }
}
}To enable Google Pay payments the following metadata tag must be added to your AndroidManifest.xml:
<meta-data
android:name="com.google.android.gms.wallet.api.enabled"
android:value="true" />While not mandatory, we recommend setting android:allowBackup to false in your AndroidManifest.xml. Failing to set it to false or to override our default value with your own will result in a manifest merge error.
Requirements:
- New Arch: Android Studio Otter 3 Feature Drop 2025.2.3
- Old Arch: Android Studio Narwhal
💡 Tip: Use JetBrains Toolbox for easy Android Studio version management.
Expo Setup
Our package cannot run in Expo Go. Instead, you need to run:
npx expo prebuildThis command compiles your app with our package included.
For Android, the repositories step above is a hard requirement to resolve dependencies. Our package provides a general-purpose plugin that appends the repositories defined in the Android Setup block above. The plugin can also append the Google Pay tag to the AndroidManifest.xml if required.
If your app already uses custom plugins that modify build.gradle or AndroidManifest.xml, we recommend extending your existing plugin or creating an additional plugin to customize adding the repositories block to fit your use case. You can find documentation on writing Expo plugins here.
The android:allowBackup tag and plugins can be set in app.json like so:
"android": {
"allowBackup": false
},
"plugins": [
[
"@checkout.com/checkout-react-native-components",
{
"enableGooglePay": true
}
]
]🧩 Components Overview
| Component | Description | Platform | Key Features | |-----------|-------------|----------|--------------| | Flow | Complete payment flow with multiple payment methods | iOS/Android | 3DS support, dynamic payment methods, built-in validation | | Card | Secure card input form | iOS/Android | Card validation, tokenization, custom styling | | Apple Pay | Native Apple Pay integration | iOS only | Seamless iOS payment experience | | Google Pay | Native Google Pay integration | Android only | Seamless Android payment experience |
⚙️ Core Configuration
CheckoutProvider Setup
Wrap your payment screen with CheckoutProvider to enable payment functionality.
Create a Payment Session and pass it to CheckoutProvider.
import {
CheckoutProvider,
CheckoutConfiguration,
Environment,
Locale
} from '@checkout.com/checkout-react-native-components';
const config: CheckoutConfiguration = {
publicKey: 'pk_test_your_public_key',
environment: 'sandbox', // or 'production'
locale: Locale.en_GB,
merchantIdentifier: 'merchant.com.your-app.name', // Required for Apple Pay
translations: {
[Locale.en_GB]: {
cardNumber: 'Card Number',
payButtonPay: 'Pay Now'
}
},
style: {
colorTokens: {
primary: '#186AFF',
background: '#FFFFFF',
border: '#E3E8F2',
error: '#E01E5A'
},
borderButtonRadius: 12,
borderFormRadius: 8
}
};
export default function PaymentScreen() {
const [paymentSession, setPaymentSession] = useState({
id: '',
payment_session_secret: ''
});
useEffect(() => {
fetchPaymentSession().then((data) => {
setPaymentSession(data);
});
}, []);
return (
<CheckoutProvider
config={config}
onSuccess={(paymentMethod, paymentID) => {
console.log('Payment successful:', { paymentMethod, paymentID });
}}
onError={(error) => {
console.error('Payment error:', error);
}}
paymentSession={paymentSession}
>
{/* Your app components */}
</CheckoutProvider>
);
}📝 Configuration Options
| Property | Type | Required | Description |
|----------|------|----------|-------------|
| publicKey | string | ✅ | Your Checkout.com public API key |
| environment | 'sandbox' \| 'production' | ✅ | Environment for API calls |
| locale | string | ❌ | Locale for UI text (defaults to English) |
| merchantIdentifier | string | ❌ | Apple Pay merchant identifier |
| translations | Record<string, Translations> | ❌ | Custom text translations |
| style | Style | ❌ | UI customization options |
📖 Component Reference
Flow Component
The Flow component provides a complete payment experience with support for multiple payment methods, 3D Secure, and dynamic payment method display.
🔧 Flow Configuration & Usage
Basic Usage
import { Flow } from '@checkout.com/checkout-react-native-components';
const PaymentScreen = () => {
return (
<CheckoutProvider config={config} paymentSession={paymentSession}>
<Flow style={{ marginVertical: 20 }} />
</CheckoutProvider>
);
};Imperative API Usage
const PaymentScreen = () => {
const flowRef = useRef<FlowRef>(null);
const handleSubmit = () => {
flowRef.current?.submit(); // Process payment
};
const handleTokenize = () => {
flowRef.current?.tokenize(); // Tokenize card
};
const updateDetails = (amount: number, currency: string | undefined) => {
// Dynamically adjust the payment amount
flowRef.current?.update({amount: amount, currency: currency });
}
return (
<CheckoutProvider config={config} paymentSession={paymentSession}>
<Flow
ref={flowRef}
config={{ showPayButton: false }} // Hide built-in pay button
/>
<Button title="Pay" onPress={handleSubmit} />
<Button title="Tokenize Card" onPress={handleTokenize} />
</CheckoutProvider>
);
};Flow Props
| Property | Type | Required | Description |
|----------|------|----------|-------------|
| config | FlowConfig | ❌ | Flow-specific configuration |
| style | ViewStyle \| ViewStyle[] | ❌ | React Native styling |
| ref | FlowRef | ❌ | Imperative API reference |
FlowConfig Options
| Property | Type | Default | Description |
|----------|------|---------|-------------|
| showPayButton | boolean | true | Show/hide the built-in pay button |
| paymentButtonAction | 'payment' \| 'tokenize' | 'payment' | Action when pay button is pressed |
Card Component
The Card component provides a secure card input form ideal for custom checkout implementations.
💳 Card Configuration & Usage
Basic Usage
import { Card, CardRef } from '@checkout.com/checkout-react-native-components';
const CardPaymentScreen = () => {
const cardRef = useRef<CardRef>(null);
const handleSubmit = () => {
cardRef.current?.submit();
};
return (
<CheckoutProvider config={config} paymentSession={paymentSession}>
<Card
ref={cardRef}
config={{ showPayButton: false }}
/>
</CheckoutProvider>
);
};Card Props
| Property | Type | Required | Description |
|----------|------|----------|-------------|
| config | CardConfig | ❌ | Card-specific configuration |
| style | ViewStyle \| ViewStyle[] | ❌ | React Native styling |
| ref | CardRef | ❌ | Imperative API reference |
CardConfig Options
| Property | Type | Default | Description |
|----------|------|---------|-------------|
| showPayButton | boolean | true | Show/hide the built-in pay button |
| paymentButtonAction | 'payment' \| 'tokenize' | 'payment' | Action when pay button is pressed |
Apple Pay Component
The Apple Pay component provides native Apple Pay integration for iOS devices.
🍎 Apple Pay Configuration & Usage
Basic Usage
import { ApplePay, CheckoutProvider } from '@checkout.com/checkout-react-native-components';
const PaymentScreen = () => {
return (
<CheckoutProvider
config={{
...config,
merchantIdentifier: 'merchant.com.your-app.name' // Required!
}}
paymentSession={paymentSession}
>
<ApplePay style={{ height: 60, marginVertical: 10 }} />
</CheckoutProvider>
);
};Apple Pay Props
| Property | Type | Required | Description |
|----------|------|----------|-------------|
| style | ViewStyle \| ViewStyle[] | ❌ | React Native styling |
📝 Note: Apple Pay requires a valid merchantIdentifier in your CheckoutConfiguration and is only available on iOS devices.
Google Pay Component
The Google Pay component provides native Google Pay integration for Android devices.
🤖 Google Pay Configuration & Usage
Basic Usage
import { CheckoutProvider, GooglePay } from '@checkout.com/checkout-react-native-components';
const PaymentScreen = () => {
return (
<CheckoutProvider config={config} paymentSession={paymentSession}>
<GooglePay />
</CheckoutProvider>
);
};Google Pay Props
| Property | Type | Required | Description |
|----------|------|----------|-------------|
| config | GooglePayConfig | ❌ | Google Pay configuration (reserved for future use) |
| style | ViewStyle \| ViewStyle[] | ❌ | React Native styling |
📝 Note: Google Pay is only available on Android devices.
🔧 Advanced Features
Imperative API
Both Flow and Card components support imperative APIs (submit and token) for programmatic control:
import { CheckoutProvider, Card, Flow, FlowRef, CardRef } from '@checkout.com/checkout-react-native-components';
const PaymentScreen = () => {
const flowRef = useRef<FlowRef>(null);
const cardRef = useRef<CardRef>(null);
// Trigger payment submission programmatically
const processPayment = () => {
flowRef.current?.submit();
};
// Tokenize card details without submitting
const tokenizeCard = () => {
cardRef.current?.tokenize();
};
// Update payment details (Wallet Payment Components only)
const updateDetails = (amount: number, currency: string) => {
flowRef.current?.update({ amount, currency });
};
return (
<CheckoutProvider config={config} paymentSession={paymentSession}>
<Flow ref={flowRef} config={{ showPayButton: false }} />
<Card ref={cardRef} config={{ showPayButton: false }} />
<Button title="Process Payment" onPress={processPayment} />
<Button title="Save Card" onPress={tokenizeCard} />
</CheckoutProvider>
);
};🎨 Customization
🎨 Complete Color Token Reference
const customStyle = {
colorTokens: {
// Primary brand color
primary: '#186AFF',
// Background colors
background: '#FFFFFF',
formBackground: '#F7F9FC',
// Border colors
border: '#E3E8F2',
formBorder: '#C8D1E0',
outline: '#91B2EE',
// State colors
error: '#E01E5A',
success: '#1AA27B',
disabled: '#B0B0B0',
// Text colors
secondary: '#545F7A',
inverse: '#FFFFFF',
// Action colors
action: '#186AFF',
// Android specific
scrolledContainer: '#F0F0F0' // Android only
}
};📏 Border Radius
const customBorders = {
borderButtonRadius: 12, // Button border radius
borderFormRadius: 8 // Form field border radius
};🔤 Custom Fonts
const fonts = {
button: {
fontFamily: 'Custom-Font',
fontSize: 14,
letterSpacing: 2,
lineHeight: 8,
},
input: {
fontFamily: 'Custom-Font',
fontSize: 14,
letterSpacing: 2,
lineHeight: 8,
},
footnote: {
fontFamily: 'Custom-Font',
fontSize: 14,
letterSpacing: 2,
lineHeight: 8,
},
label: {
fontFamily: 'Custom-Font',
fontSize: 14,
letterSpacing: 2,
lineHeight: 8,
},
subheading: {
fontFamily: 'Custom-Font',
fontSize: 14,
letterSpacing: 2,
lineHeight: 8,
},
};iOS
The SDK supports all iOS default system fonts
Android
The following built-in Android font families are supported:
- SansSerif
- Serif
- Monospace
- Cursive
- Default
🌍 Supported Locales & Custom Translations
Supported Locales
enum Locale {
ar = 'ar', // Arabic
da_DK = 'da-DK', // Danish
de_DE = 'de-DE', // German
el = 'el', // Greek
en_GB = 'en-GB', // English (UK)
es_ES = 'es-ES', // Spanish
fi_FI = 'fi-FI', // Finnish
fil_PH = 'fil-PH', // Filipino
fr_FR = 'fr-FR', // French
hi_IN = 'hi-IN', // Hindi
id_ID = 'id-ID', // Indonesian
it_IT = 'it-IT', // Italian
ja_JP = 'ja-JP', // Japanese
ms_MY = 'ms-MY', // Malay
nb_NO = 'nb-NO', // Norwegian
nl_NL = 'nl-NL', // Dutch
pt_PT = 'pt-PT', // Portuguese
sv_SE = 'sv-SE', // Swedish
th_TH = 'th-TH', // Thai
vi_VN = 'vi-VN', // Vietnamese
zh_CN = 'zh-CN', // Chinese (Simplified)
zh_HK = 'zh-HK', // Chinese (Hong Kong)
zh_TW = 'zh-TW' // Chinese (Traditional)
}Translations Interface
All available translation keys with their descriptions:
export type Translations = {
addBillingAddress?: string;
addAddress?: string;
address?: string;
addressLine1?: string;
addressLine2?: string;
billingAddress?: string;
card?: string;
cardExpiryDate?: string;
cardExpiryDateIncomplete?: string;
cardExpiryDateInvalid?: string;
cardExpiryDatePlaceholderMonth?: string;
cardExpiryDatePlaceholderYear?: string;
cardHolderName?: string;
cardNumber?: string;
cardNumberInvalid?: string;
cardNumberNotSupported?: string;
cardSecurityCode?: string;
cardSecurityCodeInvalid?: string;
cardSecurityCodePlaceholder?: string;
city?: string;
confirm?: string;
country?: string;
selectCountry?: string;
editAddress?: string;
email?: string;
emailFormatInvalid?: string;
firstName?: string;
formRequired?: string;
lastName?: string;
insufficientCharacters?: string;
noMatchesFound?: string;
optional?: string;
payButtonPay?: string;
payButtonPaymentComplete?: string;
payButtonPaymentProcessing?: string;
paymentDeclinedInvalidCustomerData?: string;
paymentDeclinedInvalidPaymentSessionData?: string;
paymentDeclinedMerchantMisconfiguration?: string;
paymentDeclinedNotEnoughFunds?: string;
paymentDeclinedTryAgain?: string;
phoneNumber?: string;
search?: string;
state?: string;
trySearchingWithAnotherTerm?: string;
useShippingAsBilling?: string;
zip?: string;
preferredSchemeCta?: string;
preferredSchemeDescription?: string;
selectState?: string;
};Custom Translations Example
const customTranslations = {
[Locale.en_GB]: {
// Address and billing
addBillingAddress: 'Add Billing Address',
addAddress: 'Add Address',
address: 'Address',
addressLine1: 'Address Line 1',
addressLine2: 'Address Line 2',
billingAddress: 'Billing Address',
// Card form labels
card: 'Card',
cardNumber: 'Card Number',
cardExpiryDate: 'MM/YY',
cardExpiryDatePlaceholderMonth: 'MM',
cardExpiryDatePlaceholderYear: 'YY',
cardSecurityCode: 'CVV',
cardSecurityCodePlaceholder: 'CVV',
cardHolderName: 'Cardholder Name',
// Personal information
firstName: 'First Name',
lastName: 'Last Name',
email: 'Email Address',
phoneNumber: 'Phone Number',
// Location fields
city: 'City',
state: 'State/Province',
zip: 'ZIP/Postal Code',
country: 'Country',
selectCountry: 'Select Country',
selectState: 'Select State',
// Actions and buttons
payButtonPay: 'Pay Now',
payButtonPaymentProcessing: 'Processing...',
payButtonPaymentComplete: 'Payment Complete',
confirm: 'Confirm',
editAddress: 'Edit Address',
search: 'Search',
// Validation and error messages
formRequired: 'This field is required',
cardNumberInvalid: 'Invalid card number',
cardNumberNotSupported: 'Card type not supported',
cardExpiryDateIncomplete: 'Expiry date incomplete',
cardExpiryDateInvalid: 'Invalid expiry date',
cardSecurityCodeInvalid: 'Invalid security code',
emailFormatInvalid: 'Invalid email format',
insufficientCharacters: 'Insufficient characters',
// Payment errors
paymentDeclinedTryAgain: 'Payment declined. Please try again.',
paymentDeclinedNotEnoughFunds: 'Insufficient funds',
paymentDeclinedInvalidCustomerData: 'Invalid payment details',
paymentDeclinedInvalidPaymentSessionData: 'Invalid payment session data',
paymentDeclinedMerchantMisconfiguration: 'Merchant configuration error',
// Search and selection
noMatchesFound: 'No matches found',
trySearchingWithAnotherTerm: 'Try searching with another term',
// Miscellaneous
optional: 'Optional',
useShippingAsBilling: 'Use shipping address as billing address',
preferredSchemeCta: 'Select Preferred Scheme',
preferredSchemeDescription: 'Please select your preferred card scheme'
}
};📡 Event Handling
📋 Complete Event Reference
const eventHandlers = {
// Component lifecycle
onReady: (paymentMethod: string) => {
console.log('Component ready for:', paymentMethod);
},
// Form validation
onChange: (paymentMethod: string, isValid: boolean, isAvailable: boolean) => {
console.log('Form state changed:', { paymentMethod, isValid, isAvailable });
// Update UI based on form validity
},
// Payment submission
onSubmit: (paymentMethod: string) => {
console.log('Payment submitted for:', paymentMethod);
// Show loading state
},
// Tokenization
onTokenized: async (tokenizationResult: TokenizationResult) => {
console.log('Card tokenized:', tokenizationResult);
if (tokenizeResult.data.card_type === 'CREDIT') {
return {
continue: false,
error: 'Credit cards are not accepted.',
};
}
await utilizeToken(tokenizationResult.token);
return { continue: true };
},
// Payment success
onSuccess: (paymentMethod: string, paymentID: string) => {
console.log('Payment successful:', { paymentMethod, paymentID });
// Navigate to success screen
},
// Error handling
onError: (error: Error) => {
console.error('Payment error:', error);
// Show error message to user
},
// Handle Submit
const handleSubmit = async (sessionData: string) => {
// Provide the `submitData` to your server-side integration for payment submission
const submitResponse = await performPaymentSubmission(submitData);
const apiCallResult: APICallResult = {
success: true,
paymentSessionSubmissionResult: submitResponse,
};
return apiCallResult;
}
};
<CheckoutProvider {...eventHandlers}>
{/* Components */}
</CheckoutProvider>🔍 Linting & formatting
This repository uses Biome for linting and formatting (replacing ESLint and Prettier). Configuration lives in the root biome.json. Each sample app under examples/ includes a biome.json that extends the root config (root: false).
Prerequisites
Clone the repository and install dependencies from the package root:
yarn installEnsure you are using the Node.js version required by the project (see sample
package.jsonenginesfields where present).
Root package scripts (library + all workspaces)
Run these from the repository root (checkout-react-native-components/):
| Script | Command | Purpose |
|--------|---------|---------|
| CI check (lint + format) | yarn check:ci | Same as CI: runs biome ci . — fails if sources need formatting or violate lint rules. Use this before pushing. |
| Lint only | yarn lint | Runs biome lint . (lint diagnostics without applying changes). |
| Format (write) | yarn format | Runs biome format --write . to apply formatting. |
| Format (verify) | yarn format:check | Runs biome format . to verify formatting without writing files. |
| Check (lint + format + assist) | yarn check | Runs biome check . (full check, no writes). |
| Auto-fix | yarn lint:fix | Runs biome check --write . to apply safe fixes and formatting. |
Some fixes are marked unsafe by Biome (for example certain type-related suggestions). Apply them only when you intend to:
yarn biome check --write --unsafe .Sample apps (examples/*)
From the root, you can run Biome for a specific workspace:
yarn workspace CheckoutRnNewArch lint
yarn workspace checkoutexponewarch format
yarn workspace shared-components lintOr cd into an example and use the same script names (lint, format, lint:fix) defined in that package’s package.json.
CI
The GitHub Actions workflow runs yarn check:ci in the lint job so that pull requests must satisfy Biome’s formatter and linter.
References
🪝 Git hooks (Lefthook)
This repository uses Lefthook so common checks run locally and stay aligned with the main CI jobs (yarn check:ci, yarn typecheck, yarn test). Configuration lives in the root lefthook.yml. Native example builds, yarn prepare (bob build), and full Jest with coverage are intentionally left to GitHub Actions.
Installing hooks
After you clone or pull, run yarn install from the repository root. The postinstall script runs lefthook install when lefthook.yml is present (this only applies when you work from a git checkout of this repo; the published npm package does not ship lefthook.yml). You can also run yarn lefthook install manually if needed.
What runs when
| Hook | Command(s) |
|------|------------|
| pre-commit | yarn biome check --staged (lint + format check on staged files only) |
| pre-push (parallel) | yarn typecheck and yarn test --onlyChanged --maxWorkers=2 |
| commit-msg | yarn commitlint --edit (conventional commits; see commitlint in package.json) |
| post-checkout | yarn install --immutable |
All of the above are skipped when the CI environment variable is set (for example in many CI systems). If your local terminal sets CI=1, hooks will not run until you unset it.
Bypassing hooks
- Disable Lefthook for a single Git invocation:
LEFTHOOK=0 git commit(orgit push). - Skip Git’s hooks entirely when you must:
git commit --no-verify/git push --no-verify.
Manual runs
yarn lefthook run pre-commit
yarn lefthook run pre-push
yarn lefthook validate📄 License
This project is licensed under the MIT License - see the LICENSE file for details.
