Embedded components framework integrations

Learn how to use Payabli’s embedded components with front-end frameworks like React and Vue

View as MarkdownOpen in Claude
Applies to:Developers

You can use Payabli’s embedded components in a React, Vue, or React Native application following the same configuration patterns as in a vanilla JavaScript application.

React

Visit the React Integration Example to see Payabli’s embedded components in a React application.

Step 1: Create the hook

Create a hook that allows you to use the embedded component and execute its methods. The hook needs to inject the Payabli library script and initialize the embedded component with the provided configuration. Make a new file for the usePayabli hook and add the following code:

1// usePayabli.ts
2import { useState, useEffect, useRef, useCallback } from "react";
3
4const useScript = (src: string) => {
5 const [isLoaded, setIsLoaded] = useState(false);
6
7 useEffect(() => {
8 const existingScript = document.querySelector(`script[src="${src}"]`);
9
10 const onLoad = () => {
11 setIsLoaded(true);
12 };
13
14 if (!existingScript) {
15 const script = document.createElement("script");
16 script.src = src;
17 script.async = true;
18
19 script.addEventListener("load", onLoad);
20
21 document.body.appendChild(script);
22
23 return () => {
24 script.removeEventListener("load", onLoad);
25 document.body.removeChild(script);
26 };
27 } else {
28 if (existingScript.getAttribute("data-loaded") === "true") {
29 setIsLoaded(true);
30 } else {
31 existingScript.addEventListener("load", onLoad);
32 }
33 }
34 }, [src]);
35
36 return isLoaded;
37};
38
39declare var PayabliComponent: any;
40
41export const usePayabli = (
42 options: any,
43 method: string,
44 parameters: any = null,
45 production: boolean = false
46) => {
47 const [payOptions, setPayOptions] = useState(options);
48 const [isInitialized, setIsInitialized] = useState(false);
49 const payComponentRef = useRef<any>(null);
50 const initCallbacks = useRef<(() => void)[]>([]); // Queue for functions waiting on initialization
51
52 const scriptSrc = production ? "https://embedded-component.payabli.com/component.js" : "https://embedded-component-sandbox.payabli.com/component.js";
53
54 const isScriptLoaded = useScript(scriptSrc);
55
56 useEffect(() => {
57 if (isScriptLoaded) {
58 payComponentRef.current = new PayabliComponent(payOptions);
59 setIsInitialized(true);
60
61 // payabliExecute queued callbacks
62 initCallbacks.current.forEach((cb) => cb());
63 initCallbacks.current = []; // Clear the queue
64 }
65 }, [isScriptLoaded, payOptions]);
66
67 useEffect(() => {
68 if (isInitialized && payComponentRef.current) {
69 payComponentRef.current.updateConfig(payOptions);
70 }
71 }, [isInitialized, payOptions]);
72
73 const payabliReinit = useCallback(() => {
74 if (isInitialized && payComponentRef.current) {
75 payComponentRef.current.payabliExec("reinit");
76 }
77 }, [isInitialized]);
78
79 const payabliExec = useCallback(() => {
80 const payabliExecuteMethod = () => {
81 if (parameters != null) {
82 payComponentRef.current.payabliExec(method, parameters);
83 } else {
84 payComponentRef.current.payabliExec(method);
85 }
86 };
87
88 if (isInitialized && payComponentRef.current) {
89 payabliExecuteMethod();
90 } else {
91 initCallbacks.current.push(payabliExecuteMethod); // Queue the payabliExecution
92 }
93 }, [isInitialized, method, parameters]);
94
95 return [payOptions, setPayOptions, payabliExec, payabliReinit];
96};

Step 2: Create the component

Create a new PayabliCheckout component that passes in the configuration object for the embedded component to the usePayabli hook. The PayabliCheckout component uses the payabliExec function to execute the embedded component’s method. Create a new file in the same directory and add the following code:

There are multiple types of embedded components with different use cases. See the Embedded Components Overview to decide which component type is best for you.

1// PayabliCheckout.tsx
2import { usePayabli } from './usePayabli';
3
4export const PayabliCheckout = () => {
5 const token = "o.z8j8aaztW9tUtUg4d.."
6 const entryPoint = "bozeman-aikido"
7 const rootContainer = "pay-component-1"
8 const payabliButton = "btnx"
9
10 const [payabliConfig, setPayabliConfig, payabliExec] = usePayabli({
11 type: "methodEmbedded",
12 rootContainer: rootContainer,
13 defaultOpen: 'card', // offering only Card method - Embedded UI can only show a payment method
14 // customCssUrl: "your url to a custom css file",
15 token: token,
16 entryPoint: entryPoint,
17 card: {
18 enabled: true,
19 amex: true,
20 discover: true,
21 visa: true,
22 mastercard: true,
23 jcb: true,
24 diners: true,
25 inputs: { // here we are customizing the input fields
26 cardHolderName: {
27 label: "NAME ON CARD",
28 placeholder: "",
29 floating: false,
30 value: "John Doe",
31 size: 12,
32 row: 0,
33 order: 0
34 },
35 cardNumber: {
36 label: "CARD NUMBER",
37 placeholder: "1234 1234 1234 1234",
38 floating: false,
39 size: 6,
40 row: 1,
41 order: 0
42 },
43 cardExpirationDate: {
44 label: "EXPIRATION DATE",
45 placeholder: "MM/YY",
46 floating: false,
47 size: 6,
48 row: 1,
49 order: 1
50 },
51 cardCvv: {
52 label: "CVV/CVC",
53 placeholder: "CVV/CVC",
54 floating: false,
55 size: 6,
56 row: 2,
57 order: 0,
58 },
59 cardZipcode: {
60 label: "ZIP/POSTAL CODE",
61 placeholder: "ZIP/POSTAL CODE",
62 floating: false,
63 size: 6,
64 row: 2,
65 order: 1,
66 country: ["us", "ca"],
67 }
68 }
69 },
70 ach: {
71 enabled: false,
72 checking: true,
73 savings: true
74 },
75 customerData: {
76 customerNumber: "00001",
77 firstName: "John",
78 lastName: "Doe",
79 billingEmail: "johndoe@email.com"
80 },
81 functionCallBackSuccess: (response: any) => {
82 const containerEl = document.getElementById(rootContainer);
83 const responseText = JSON.stringify(response.responseText);
84 const responseData = JSON.stringify(response.responseData);
85 alert(responseText + " " + responseData);
86 containerEl!.innerHTML += `
87 <hr/>
88 <p><b>Embedded Component Response:</b></p>
89 <p>${responseText}</p>
90 <p>${responseData}</p>
91 <hr/>
92 `;
93 },
94 functionCallBackReady: (data: any) => {
95 var btn = document.getElementById(payabliButton);
96 if (data[1] === true) {
97 btn!.classList.remove("hidden");
98 } else {
99 if (!btn!.classList.contains("hidden")) {
100 btn!.classList.add("hidden");
101 }
102 }
103 },
104 functionCallBackError: (errors: any) => {
105 alert('Error!');
106 console.log(errors);
107 }
108 },
109 "pay", {
110 paymentDetails: {
111 totalAmount: 100,
112 serviceFee: 0,
113 categories: [
114 {
115 label: "payment",
116 amount: 100,
117 qty: 1,
118 },
119 ],
120 },
121 })
122
123 return (
124 <div>
125 <div id="pay-component-1"></div>
126 <button id="btnx" className="hidden" onClick={payabliExec}>Pay</button>
127 <button onClick={() => setPayabliConfig({
128 ...payabliConfig,
129 card: {
130 ...payabliConfig.card,
131 inputs: {
132 ...payabliConfig.card.inputs,
133 cardHolderName: {
134 ...payabliConfig.card.inputs.cardHolderName,
135 value: "Johnny Dover"
136 }
137 }
138 }
139 })}>Switch to Johnny Dover</button>
140 </div>
141 )
142}
1// PayabliCheckout.tsx
2import { usePayabli } from './usePayabli.ts';
3
4export const PayabliCheckout = () => {
5 const token = "o.z8j8aaztW9tUtUg4d.."
6 const entryPoint = "bozeman-aikido"
7
8 const [payabliConfig, setPayabliConfig, payabliExec, payabliReinit] = usePayabli({
9 type: "methodLightbox",
10 rootContainer: "pay-component-1",
11 buttonLabelInModal: 'Save Payment Method',
12 defaultOpen: 'ach',
13 hideComponent: true,
14 token: token,
15 entryPoint: entryPoint,
16 card: {
17 enabled: true,
18 amex: true,
19 discover: true,
20 visa: true,
21 mastercard: true,
22 jcb: true,
23 diners: true
24 },
25 ach: {
26 enabled: true,
27 checking: true,
28 savings: false
29 },
30 customerData: {
31 customerNumber: "00001",
32 firstName: "John",
33 lastName: "Doe",
34 billingEmail: "johndoe@email.com"
35 },
36
37 functionCallBackSuccess: (response: any) => {
38 // This callback covers both 2XX and 4XX responses
39 console.log(response);
40 switch (response.responseText) {
41 case "Success":
42 // Tokenization was successful
43 alert(`Success: ${response.responseData.resultText}`);
44 break;
45 case "Declined":
46 // Tokenization failed due to processor decline or validation errors
47 // Recommend reinitialization of the component so that the user can try again
48 // with different card data
49 alert(`Declined: ${response.responseData.resultText}`);
50 payabliReinit()
51 break;
52 default:
53 // Other response text. These are normally errors with Payabli internal validations
54 // before processor engagement
55 // We recommend reinitializing the component.
56 // If the problem persists, contact Payabli to help debug
57 alert(`Error: ${response.responseText}`);
58 payabliReinit()
59 break;
60 }
61 },
62
63 functionCallBackError: (errors: any) => {
64 // This callback covers 5XX response or parsing errors
65 // We recommend reinitializing the component.
66 // If the problem persists, contact Payabli to help debug
67 console.log(errors);
68 payabliReinit()
69 }
70 },
71 "pay", {
72 paymentDetails: {
73 totalAmount: 100,
74 serviceFee: 0,
75 categories: [
76 {
77 label: "payment",
78 amount: 100,
79 qty: 1,
80 },
81 ],
82 },
83 })
84
85 return (
86 <div>
87 <div id="pay-component-1"></div>
88 <button onClick={payabliExec}>Pay</button>
89 <button onClick={() => setPayabliConfig({
90 ...payabliConfig,
91 card: {
92 ...payabliConfig.card,
93 enabled: !payabliConfig.card.enabled
94 }
95 })}>Toggle Card Payments</button>
96 </div>
97 )
98}

Types

The hook receives the following arguments:

Arguments
options
anyRequired

The configuration object for the embedded component. See the configuration reference for the component type you are using.

method
stringRequired

The method to execute in payabliExec. See the field for more information.

parameters
any

An optional object that contains objects to pass to the method. See the paymentMethod, paymentDetails, or customerData objects for more information.

production
booleanDefaults to false

A boolean value that determines whether to use the production or sandbox environment.

The hook returns an array with the following elements:

Return Values
payOptions
any

The configuration object for the embedded component. See the configuration reference for the component type you are using.

setPayOptions
(options: any) => void

A function to update the configuration object for the embedded component. This allows you to dynamically change the options after initialization.

payabliExec
() => void

A function to execute the embedded component’s method. This will call the method specified in the method argument passed to the hook.

payabliReinit
() => void

A function to reinitialize the embedded component.

Vue

Visit the Vue integration example to see Payabli’s embedded components in a Vue application.

Step 1: Create the composable

Create a composable that allows you to use the embedded component and execute its methods. The composable needs to inject the Payabli library script and initialize the embedded component with the provided configuration. Make a new file for the usePayabli composable and add the following code:

TypeScript
1// usePayabli.ts
2import { ref, reactive, onMounted, watchEffect } from 'vue';
3
4const loadedScripts = new Set<string>();
5
6const useScript = (src: string) => {
7 const isLoaded = ref(false);
8
9 onMounted(() => {
10 if (loadedScripts.has(src)) {
11 isLoaded.value = true;
12 return;
13 }
14
15 const existingScript = document.querySelector(`script[src="${src}"]`);
16
17 const handleLoad = () => {
18 loadedScripts.add(src);
19 isLoaded.value = true;
20 script.setAttribute("data-loaded", "true");
21 };
22
23 let script: HTMLScriptElement;
24
25 if (!existingScript) {
26 script = document.createElement("script");
27 script.src = src;
28 script.async = true;
29 script.addEventListener("load", handleLoad);
30 document.body.appendChild(script);
31 } else {
32 if (existingScript.getAttribute("data-loaded") === "true") {
33 isLoaded.value = true;
34 } else {
35 existingScript.addEventListener("load", handleLoad);
36 }
37 }
38 });
39
40 return isLoaded;
41};
42
43declare var PayabliComponent: any;
44
45export const usePayabli = (
46 options: any,
47 method: string,
48 parameters: any = null,
49 production = false
50) => {
51 const payOptions = reactive({ ...options });
52 const isInitialized = ref(false);
53 const payComponentRef = ref<any>(null);
54 const initCallbacks: (() => void)[] = [];
55
56 const scriptSrc = production
57 ? "https://embedded-component.payabli.com/component.js"
58 : "https://embedded-component-sandbox.payabli.com/component.js";
59
60 const isScriptLoaded = useScript(scriptSrc);
61
62 const initPayabli = () => {
63 if (!isScriptLoaded.value || isInitialized.value) return;
64
65 payComponentRef.value = new PayabliComponent(payOptions);
66 isInitialized.value = true;
67
68 initCallbacks.splice(0).forEach(cb => cb());
69 };
70
71 watchEffect(() => {
72 if (isScriptLoaded.value) {
73 initPayabli();
74 }
75 });
76
77 watchEffect(() => {
78 if (isInitialized.value && payComponentRef.value) {
79 payComponentRef.value.updateConfig(payOptions);
80 }
81 });
82
83 const payabliReinit = () => {
84 if (isInitialized.value && payComponentRef.value) {
85 payComponentRef.value.payabliExec("reinit");
86 }
87 };
88
89 const payabliExec = () => {
90 const exec = () => {
91 if (!payComponentRef.value) return;
92
93 if (payOptions.type === "methodEmbedded") {
94 if (parameters != null) {
95 payComponentRef.value.payabliExec(method, parameters);
96 } else {
97 payComponentRef.value.payabliExec(method);
98 }
99 } else if (
100 payOptions.type === "methodLightbox" ||
101 payOptions.type === "vterminal"
102 ) {
103 payComponentRef.value.showModal();
104 }
105 };
106
107 if (isInitialized.value) {
108 exec();
109 } else {
110 initCallbacks.push(exec);
111 }
112 };
113
114 return [payOptions, payabliExec, payabliReinit] as const;
115};

Step 2: Create the component

Create a new PayabliCheckout component that passes in the configuration object for the embedded component to the usePayabli composable. The PayabliCheckout component uses the payabliExec function to execute the embedded component’s method. Create a new file in the same directory and add the following code:

Vue
1<template>
2 <div>
3 <div id="pay-component-1"></div>
4 <button id="btnx" class="hidden" @click="payabliExec">Pay</button>
5 <button @click.prevent="switchToJohnnyDover">Switch to Johnny Dover</button>
6 </div>
7</template>
8
9<script setup>
10import { ref, onMounted } from 'vue';
11import { usePayabli } from '../composables/usePayabli.ts';
12
13const token = "o.z8j8aaztW9tUtUg4d..";
14const entryPoint = "bozeman-aikido";
15const rootContainer = "pay-component-1";
16const payabliButton = "btnx";
17
18const [payabliConfig, payabliExec] = usePayabli({
19 type: "methodEmbedded",
20 rootContainer: rootContainer,
21 defaultOpen: 'card',
22 token: token,
23 entryPoint: entryPoint,
24 card: {
25 enabled: true,
26 amex: true,
27 discover: true,
28 visa: true,
29 mastercard: true,
30 jcb: true,
31 diners: true,
32 inputs: {
33 cardHolderName: {
34 label: "NAME ON CARD",
35 placeholder: "",
36 floating: false,
37 value: "John Doe",
38 size: 12,
39 row: 0,
40 order: 0
41 },
42 cardNumber: {
43 label: "CARD NUMBER",
44 placeholder: "1234 1234 1234 1234",
45 floating: false,
46 size: 6,
47 row: 1,
48 order: 0
49 },
50 cardExpirationDate: {
51 label: "EXPIRATION DATE",
52 placeholder: "MM/YY",
53 floating: false,
54 size: 6,
55 row: 1,
56 order: 1
57 },
58 cardCvv: {
59 label: "CVV/CVC",
60 placeholder: "CVV/CVC",
61 floating: false,
62 size: 6,
63 row: 2,
64 order: 0,
65 },
66 cardZipcode: {
67 label: "ZIP/POSTAL CODE",
68 placeholder: "ZIP/POSTAL CODE",
69 floating: false,
70 size: 6,
71 row: 2,
72 order: 1,
73 country: ["us", "ca"],
74 }
75 }
76 },
77 ach: {
78 enabled: false,
79 checking: true,
80 savings: true
81 },
82 customerData: {
83 customerNumber: "00001",
84 firstName: "John",
85 lastName: "Doe",
86 billingEmail: "johndoe@email.com"
87 },
88 functionCallBackSuccess: (response) => {
89 const containerEl = document.getElementById(rootContainer);
90 const responseText = JSON.stringify(response.responseText);
91 const responseData = JSON.stringify(response.responseData);
92 alert(responseText + " " + responseData);
93 containerEl.innerHTML += `
94 <hr/>
95 <p><b>Embedded Component Response:</b></p>
96 <p>${responseText}</p>
97 <p>${responseData}</p>
98 <hr/>
99 `;
100 },
101 functionCallBackReady: (data) => {
102 const btn = document.getElementById(payabliButton);
103 if (data[1] === true && btn) {
104 btn.classList.remove("hidden");
105 } else if (btn) {
106 btn.classList.add("hidden");
107 }
108 },
109 functionCallBackError: (errors) => {
110 alert('Error!');
111 console.log(errors);
112 }
113},
114"pay", {
115 paymentDetails: {
116 totalAmount: 100,
117 serviceFee: 0,
118 categories: [
119 {
120 label: "payment",
121 amount: 100,
122 qty: 1,
123 },
124 ],
125 },
126});
127
128const switchToJohnnyDover = () => {
129 payabliConfig.card.inputs.cardHolderName.value = "Johnny Dover";
130};
131</script>
132
133<style scoped>
134.hidden {
135 display: none;
136}
137</style>

Types

The composable receives the following arguments:

Arguments
options
anyRequired

The configuration object for the embedded component. See the configuration reference for the component type you are using.

method
stringRequired

The method to execute in payabliExec. See the field for more information.

parameters
any

An optional object that contains objects to pass to the method. See the paymentMethod, paymentDetails, or customerData objects for more information.

production
booleanDefaults to false

A boolean value that determines whether to use the production or sandbox environment.

The composable returns an array with the following elements:

Return Values
payOptions
any

The configuration object for the embedded component. See the configuration reference for the component type you are using.

payabliExec
() => void

A function to execute the embedded component’s method. This will call the method specified in the method argument passed to the hook.

payabliReinit
() => void

A function to reinitialize the embedded component.

React Native

Payabli offers a React Native example app built with Expo that demonstrates how to render and use Payabli’s embedded components in a React Native environment. This section covers the file structure of the React Native example app and how to run it locally. Visit the React Native integration example to see the source code on GitHub.

File structure

To use Payabli’s embedded components in a React Native application, you must render them inside of a <WebView> component. The React Native example app contains utility files to render the embedded component inside of a <WebView>, and demo files that show how to use the utility files.

Utility files

The React Native example contains utility files that help to render the embedded component inside of a <WebView> and communicate between the React Native app and the embedded component.

This file contains the configuration object for the embedded component. To customize fields and payment methods, update the configuration in this file. For more information on the configuration object and its fields, see the configuration reference for the component type you are using.

This file contains functions that receive messages from the embedded component in the React Native app. It also defines the shape of messages received from the embedded component.

This file initializes the embedded component. It sets up the message bridge in the embedded component’s <WebView> so it can send messages to the React Native app. It works with bridge.ts to support communication between the embedded component and the app.

This file contains the TypeScript types used in the React Native example. These types include customer data shapes and payment method values.

This hook composes the utility files into reusable embedded component logic. It initializes the component and wires up the WebView integration.

This component renders Payabli’s embedded component inside a React Native <WebView>. It uses the usePayabliWebView hook to initialize the component and handle app communication.

Demo files

The React Native example contains demo files that show how to use the previous utility files to render the embedded component and handle its callbacks. These files don’t contain core logic to render Payabli’s embedded components or process payments. You can remove these files without affecting the functionality of the embedded component in your app.

This demo component renders Payabli’s embedded component with PayabliEmbeddedWebView. The PayabliCheckout component is a screen with three stages:

1

Review

The user can review their order details and edit transaction details. The order details and transaction data are passed into the embedded component’s setup functionality.

review page of React Native example app
Review stage
2

Payment

The Payabli embedded component is rendered inside a <WebView>. The user can enter their payment information and submit the transaction.

payment page of React Native example app
Payment stage
3

Result

The Payabli embedded component sends a message to the React Native app with the transaction result. The user sees the result of their transaction.

result page of React Native example app
Result stage

This demo component is the home page of the React Native example app. Click Checkout to see Payabli’s embedded component in action.

This demo hook manages the checkout state in the PayabliCheckout component. It manages the order details, transaction data, and current stage of the checkout flow.

File reference

See the table for a reference of the file structure of the React Native example app along with links to source code:

FilePathSource
config.tslib/payabli/View source
bridge.tslib/payabli/View source
bootstrap.tslib/payabli/View source
model.tslib/payabli/View source
usePayabliWebView.tshooks/View source
PayabliEmbeddedWebView.tsxcomponents/View source
PayabliCheckout.tsxcomponents/View source
HomePage.tsxcomponents/View source
useCheckoutDemo.tshooks/View source

Run the app locally

This section covers how to run the React Native example app locally on your machine.

Dependencies

Before you begin, make sure you have the following installed on your machine:

To run the app in your development environment, you need to set up an iOS or Android emulator. See the Expo docs for instructions on how to set up your environment for React Native development.

To run the app on a phone, see the Expo docs for instructions on how to set up Expo Go on your device.

Set up the app

To run the React Native example app locally, follow these steps:

1

Clone the repository

Clone the Payabli examples repository to your local machine:

$git clone https://github.com/payabli/examples
3

Install dependencies

Install the dependencies for the React Native example app:

$npm install
4

Copy environment template

Copy the environment variable template file:

$cp .env.example .env
5

Fill in environment variables

Open the .env file and fill in the required environment variables:

PAYABLI_API_KEY=your-api-key-here
PAYABLI_ENTRY_POINT=your-entry-point-here
6

Run the app

Start the React Native example app on your desired platform and environment:

$npm run ios
$npm run android
$npm start

This command starts the Expo development server and displays a QR code in your terminal. Scan the QR code to open the app in Expo Go on your phone.

7

View the app

You should now see the app running in your emulator, and you can navigate to the checkout screen to see Payabli’s embedded component in action.

You just set up the React Native example app to run locally on your machine! Use this example app as a reference for your own React Native projects.

See these related resources to help you get the most out of Payabli.