Embedded components framework integrations

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

Applies to:Developers

You can use Payabli’s embedded components in a React or Vue 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.z8j8aaztW9tUtUg4dlVeYAx+L2MazOFGr0DY8yuK3u79MCYlGK4/q0t5AD1UgLAjXOohnxN8VTZfPswyZcwtChGNn1a8jFMmYWHmLN2cPDW9IrBt1RtrSuu+85HJI+4kML5sIk9SYvULDAU2k0X0E1KFYcPwjmmkUjktrEGtz48XCUM70aKUupkrTh8nL7CXpAXATzVUZ2gEld9jGINwECPPLWmu+cZ4CJb7QMJxnzKFD073+nq/eL+pMth7+u/SkmAWC0+jn8y+Lf6T5Q5PqB6wN7Mvosp8g7U7lbEW2wC0DA92pjblfDHVJOQUkjgT7B1GvryMokLvBjoiaLhKa55iKZE1YDlyqruILkoNF+zGSPS9r17qU6w4ziKhoMdSPzPBJBlLhQhz3MVANXbjfEfJwmtr/JJ1uStUfBFJ710cS1x7goxMJO/cl+q+LVtPy788EKFkgMc5OjfBNCsNL+dBDVbK5CiIJUSbOFzdqdjY/VJ14MEodsHYOwMAjuF4.KRFMeEj0SOur8MLZ362c/UZ/U/Az3CSUkr3/8EVDE6Y="
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.z8j8aaztW9tUtUg4dlVeYAx+L2MazOFGr0DY8yuK3u79MCYlGK4/q0t5AD1UgLAjXOohnxN8VTZfPswyZcwtChGNn1a8jFMmYWHmLN2cPDW9IrBt1RtrSuu+85HJI+4kML5sIk9SYvULDAU2k0X0E1KFYcPwjmmkUjktrEGtz48XCUM70aKUupkrTh8nL7CXpAXATzVUZ2gEld9jGINwECPPLWmu+cZ4CJb7QMJxnzKFD073+nq/eL+pMth7+u/SkmAWC0+jn8y+Lf6T5Q5PqB6wN7Mvosp8g7U7lbEW2wC0DA92pjblfDHVJOQUkjgT7B1GvryMokLvBjoiaLhKa55iKZE1YDlyqruILkoNF+zGSPS9r17qU6w4ziKhoMdSPzPBJBlLhQhz3MVANXbjfEfJwmtr/JJ1uStUfBFJ710cS1x7goxMJO/cl+q+LVtPy788EKFkgMc5OjfBNCsNL+dBDVbK5CiIJUSbOFzdqdjY/VJ14MEodsHYOwMAjuF4.KRFMeEj0SOur8MLZ362c/UZ/U/Az3CSUkr3/8EVDE6Y="
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
PayabliEmbeddedMethodOptionsRequired

The configuration object for the embedded component.

method
stringRequired

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

parameters
PayabliEmbeddedComponentParameters

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
PayabliEmbeddedMethodOptions

The configuration object for the embedded component.

setPayOptions
(options: PayabliEmbeddedMethodOptions) => 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.z8j8aaztW9tUtUg4dlVeYAx+L2MazOFGr0DY8yuK3u79MCYlGK4/q0t5AD1UgLAjXOohnxN8VTZfPswyZcwtChGNn1a8jFMmYWHmLN2cPDW9IrBt1RtrSuu+85HJI+4kML5sIk9SYvULDAU2k0X0E1KFYcPwjmmkUjktrEGtz48XCUM70aKUupkrTh8nL7CXpAXATzVUZ2gEld9jGINwECPPLWmu+cZ4CJb7QMJxnzKFD073+nq/eL+pMth7+u/SkmAWC0+jn8y+Lf6T5Q5PqB6wN7Mvosp8g7U7lbEW2wC0DA92pjblfDHVJOQUkjgT7B1GvryMokLvBjoiaLhKa55iKZE1YDlyqruILkoNF+zGSPS9r17qU6w4ziKhoMdSPzPBJBlLhQhz3MVANXbjfEfJwmtr/JJ1uStUfBFJ710cS1x7goxMJO/cl+q+LVtPy788EKFkgMc5OjfBNCsNL+dBDVbK5CiIJUSbOFzdqdjY/VJ14MEodsHYOwMAjuF4.KRFMeEj0SOur8MLZ362c/UZ/U/Az3CSUkr3/8EVDE6Y=";
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
PayabliEmbeddedMethodOptionsRequired

The configuration object for the embedded component.

method
stringRequired

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

parameters
PayabliEmbeddedComponentParameters

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
PayabliEmbeddedMethodOptions

The configuration object for the embedded component.

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.