# Embedded components framework integrations > Learn how to use Payabli's embedded components with front-end frameworks like React and Vue 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](https://github.com/payabli/examples/tree/main/react-integration) 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: ```ts TypeScript // usePayabli.ts import { useState, useEffect, useRef, useCallback } from "react"; const useScript = (src: string) => { const [isLoaded, setIsLoaded] = useState(false); useEffect(() => { const existingScript = document.querySelector(`script[src="${src}"]`); const onLoad = () => { setIsLoaded(true); }; if (!existingScript) { const script = document.createElement("script"); script.src = src; script.async = true; script.addEventListener("load", onLoad); document.body.appendChild(script); return () => { script.removeEventListener("load", onLoad); document.body.removeChild(script); }; } else { if (existingScript.getAttribute("data-loaded") === "true") { setIsLoaded(true); } else { existingScript.addEventListener("load", onLoad); } } }, [src]); return isLoaded; }; declare var PayabliComponent: any; export const usePayabli = ( options: any, method: string, parameters: any = null, production: boolean = false ) => { const [payOptions, setPayOptions] = useState(options); const [isInitialized, setIsInitialized] = useState(false); const payComponentRef = useRef(null); const initCallbacks = useRef<(() => void)[]>([]); // Queue for functions waiting on initialization const scriptSrc = production ? "https://embedded-component.payabli.com/component.js" : "https://embedded-component-sandbox.payabli.com/component.js"; const isScriptLoaded = useScript(scriptSrc); useEffect(() => { if (isScriptLoaded) { payComponentRef.current = new PayabliComponent(payOptions); setIsInitialized(true); // payabliExecute queued callbacks initCallbacks.current.forEach((cb) => cb()); initCallbacks.current = []; // Clear the queue } }, [isScriptLoaded, payOptions]); useEffect(() => { if (isInitialized && payComponentRef.current) { payComponentRef.current.updateConfig(payOptions); } }, [isInitialized, payOptions]); const payabliReinit = useCallback(() => { if (isInitialized && payComponentRef.current) { payComponentRef.current.payabliExec("reinit"); } }, [isInitialized]); const payabliExec = useCallback(() => { const payabliExecuteMethod = () => { if (parameters != null) { payComponentRef.current.payabliExec(method, parameters); } else { payComponentRef.current.payabliExec(method); } }; if (isInitialized && payComponentRef.current) { payabliExecuteMethod(); } else { initCallbacks.current.push(payabliExecuteMethod); // Queue the payabliExecution } }, [isInitialized, method, parameters]); return [payOptions, setPayOptions, payabliExec, payabliReinit]; }; ``` ```js JavaScript // usePayabli.js import { useState, useEffect, useRef, useCallback } from "react"; const useScript = (src) => { const [isLoaded, setIsLoaded] = useState(false); useEffect(() => { const existingScript = document.querySelector(`script[src="${src}"]`); const onLoad = () => { setIsLoaded(true); }; if (!existingScript) { const script = document.createElement("script"); script.src = src; script.async = true; script.addEventListener("load", onLoad); document.body.appendChild(script); return () => { script.removeEventListener("load", onLoad); document.body.removeChild(script); }; } else { if (existingScript.getAttribute("data-loaded") === "true") { setIsLoaded(true); } else { existingScript.addEventListener("load", onLoad); } } }, [src]); return isLoaded; }; export const usePayabli = ( options, method, parameters = null, production = false ) => { const [payOptions, setPayOptions] = useState(options); const [isInitialized, setIsInitialized] = useState(false); const payComponentRef = useRef(null); const initCallbacks = useRef([]); // Queue for functions waiting on initialization const scriptSrc = production ? "https://embedded-component.payabli.com/component.js" : "https://embedded-component-sandbox.payabli.com/component.js"; const isScriptLoaded = useScript(scriptSrc); useEffect(() => { if (isScriptLoaded) { payComponentRef.current = new PayabliComponent(payOptions); setIsInitialized(true); // Execute queued callbacks initCallbacks.current.forEach((cb) => cb()); initCallbacks.current = []; // Clear the queue } }, [isScriptLoaded, payOptions]); useEffect(() => { if (isInitialized && payComponentRef.current) { payComponentRef.current.updateConfig(payOptions); } }, [isInitialized, payOptions]); const payabliReinit = useCallback(() => { if (isInitialized && payComponentRef.current) { payComponentRef.current.payabliExec("reinit"); } }, [isInitialized]); const payabliExec = useCallback(() => { const payabliExecuteMethod = () => { if (parameters != null) { payComponentRef.current[method](parameters); } else { payComponentRef.current[method](); } }; if (isInitialized && payComponentRef.current) { payabliExecuteMethod(); } else { initCallbacks.current.push(payabliExecuteMethod); // Queue the execution } }, [isInitialized, method, parameters]); return [payOptions, setPayOptions, payabliExec, payabliReinit]; }; ``` ### 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](/guides/pay-in-components-overview#choose-a-component) to decide which component type is best for you. ```tsx TSX // PayabliCheckout.tsx import { usePayabli } from './usePayabli'; export const PayabliCheckout = () => { const token = "o.z8j8aaztW9tUtUg4d.." const entryPoint = "bozeman-aikido" const rootContainer = "pay-component-1" const payabliButton = "btnx" const [payabliConfig, setPayabliConfig, payabliExec] = usePayabli({ type: "methodEmbedded", rootContainer: rootContainer, defaultOpen: 'card', // offering only Card method - Embedded UI can only show a payment method // customCssUrl: "your url to a custom css file", token: token, entryPoint: entryPoint, card: { enabled: true, amex: true, discover: true, visa: true, mastercard: true, jcb: true, diners: true, inputs: { // here we are customizing the input fields cardHolderName: { label: "NAME ON CARD", placeholder: "", floating: false, value: "John Doe", size: 12, row: 0, order: 0 }, cardNumber: { label: "CARD NUMBER", placeholder: "1234 1234 1234 1234", floating: false, size: 6, row: 1, order: 0 }, cardExpirationDate: { label: "EXPIRATION DATE", placeholder: "MM/YY", floating: false, size: 6, row: 1, order: 1 }, cardCvv: { label: "CVV/CVC", placeholder: "CVV/CVC", floating: false, size: 6, row: 2, order: 0, }, cardZipcode: { label: "ZIP/POSTAL CODE", placeholder: "ZIP/POSTAL CODE", floating: false, size: 6, row: 2, order: 1, country: ["us", "ca"], } } }, ach: { enabled: false, checking: true, savings: true }, customerData: { customerNumber: "00001", firstName: "John", lastName: "Doe", billingEmail: "johndoe@email.com" }, functionCallBackSuccess: (response: any) => { const containerEl = document.getElementById(rootContainer); const responseText = JSON.stringify(response.responseText); const responseData = JSON.stringify(response.responseData); alert(responseText + " " + responseData); containerEl!.innerHTML += `

Embedded Component Response:

${responseText}

${responseData}


`; }, functionCallBackReady: (data: any) => { var btn = document.getElementById(payabliButton); if (data[1] === true) { btn!.classList.remove("hidden"); } else { if (!btn!.classList.contains("hidden")) { btn!.classList.add("hidden"); } } }, functionCallBackError: (errors: any) => { alert('Error!'); console.log(errors); } }, "pay", { paymentDetails: { totalAmount: 100, serviceFee: 0, categories: [ { label: "payment", amount: 100, qty: 1, }, ], }, }) return (
) } ``` ```jsx JSX // PayabliCheckout.jsx import { usePayabli } from './usePayabli'; export const PayabliCheckout = () => { const token = "o.z8j8aaztW9tUtUg4d.." const entryPoint = "bozeman-aikido" const rootContainer = "pay-component-1" const payabliButton = "btnx" const [payabliConfig, setPayabliConfig, payabliExec] = usePayabli({ type: "methodEmbedded", rootContainer: rootContainer, defaultOpen: 'card', // offering only Card method - Embedded UI can only show a payment method // customCssUrl: "your url to a custom css file", token: token, entryPoint: entryPoint, card: { enabled: true, amex: true, discover: true, visa: true, mastercard: true, jcb: true, diners: true, inputs: { // here we are customizing the input fields cardHolderName: { label: "NAME ON CARD", placeholder: "", floating: false, value: "John Doe", size: 12, row: 0, order: 0 }, cardNumber: { label: "CARD NUMBER", placeholder: "1234 1234 1234 1234", floating: false, size: 6, row: 1, order: 0 }, cardExpirationDate: { label: "EXPIRATION DATE", placeholder: "MM/YY", floating: false, size: 6, row: 1, order: 1 }, cardCvv: { label: "CVV/CVC", placeholder: "CVV/CVC", floating: false, size: 6, row: 2, order: 0, }, cardZipcode: { label: "ZIP/POSTAL CODE", placeholder: "ZIP/POSTAL CODE", floating: false, size: 6, row: 2, order: 1, country: ["us", "ca"], } } }, ach: { enabled: false, checking: true, savings: true }, customerData: { customerNumber: "00001", firstName: "John", lastName: "Doe", billingEmail: "johndoe@email.com" }, functionCallBackSuccess: (response) => { const containerEl = document.getElementById(rootContainer); const responseText = JSON.stringify(response.responseText); const responseData = JSON.stringify(response.responseData); alert(responseText + " " + responseData); containerEl.innerHTML += `

Embedded Component Response:

${responseText}

${responseData}


`; }, functionCallBackReady: (data) => { var btn = document.getElementById(payabliButton); if (data[1] === true) { btn.classList.remove("hidden"); } else { if (!btn.classList.contains("hidden")) { btn.classList.add("hidden"); } } }, functionCallBackError: (errors) => { alert('Error!'); console.log(errors); } }, "pay", { paymentDetails: { totalAmount: 100, serviceFee: 0, categories: [ { label: "payment", amount: 100, qty: 1, }, ], }, }) return (
) } ```
```tsx TSX // PayabliCheckout.tsx import { usePayabli } from './usePayabli.ts'; export const PayabliCheckout = () => { const token = "o.z8j8aaztW9tUtUg4d.." const entryPoint = "bozeman-aikido" const [payabliConfig, setPayabliConfig, payabliExec, payabliReinit] = usePayabli({ type: "methodLightbox", rootContainer: "pay-component-1", buttonLabelInModal: 'Save Payment Method', defaultOpen: 'ach', hideComponent: true, token: token, entryPoint: entryPoint, card: { enabled: true, amex: true, discover: true, visa: true, mastercard: true, jcb: true, diners: true }, ach: { enabled: true, checking: true, savings: false }, customerData: { customerNumber: "00001", firstName: "John", lastName: "Doe", billingEmail: "johndoe@email.com" }, functionCallBackSuccess: (response: any) => { // This callback covers both 2XX and 4XX responses console.log(response); switch (response.responseText) { case "Success": // Tokenization was successful alert(`Success: ${response.responseData.resultText}`); break; case "Declined": // Tokenization failed due to processor decline or validation errors // Recommend reinitialization of the component so that the user can try again // with different card data alert(`Declined: ${response.responseData.resultText}`); payabliReinit() break; default: // Other response text. These are normally errors with Payabli internal validations // before processor engagement // We recommend reinitializing the component. // If the problem persists, contact Payabli to help debug alert(`Error: ${response.responseText}`); payabliReinit() break; } }, functionCallBackError: (errors: any) => { // This callback covers 5XX response or parsing errors // We recommend reinitializing the component. // If the problem persists, contact Payabli to help debug console.log(errors); payabliReinit() } }, "pay", { paymentDetails: { totalAmount: 100, serviceFee: 0, categories: [ { label: "payment", amount: 100, qty: 1, }, ], }, }) return (
) } ``` ```jsx JSX // PayabliCheckout.jsx import { usePayabli } from './usePayabli.js'; export const PayabliCheckout = () => { const token = "o.z8j8aaztW9tUtUg4d.." const entryPoint = "bozeman-aikido" const [payabliConfig, setPayabliConfig, payabliExec, payabliReinit] = usePayabli({ type: "methodLightbox", rootContainer: "pay-component-1", buttonLabelInModal: 'Save Payment Method', defaultOpen: 'ach', hideComponent: true, token: token, entryPoint: entryPoint, card: { enabled: true, amex: true, discover: true, visa: true, mastercard: true, jcb: true, diners: true }, ach: { enabled: true, checking: true, savings: false }, customerData: { customerNumber: "00001", firstName: "John", lastName: "Doe", billingEmail: "johndoe@email.com" }, functionCallBackSuccess: (response) => { // This callback covers both 2XX and 4XX responses console.log(response); switch (response.responseText) { case "Success": // Tokenization was successful alert(`Success: ${response.responseData.resultText}`); break; case "Declined": // Tokenization failed due to processor decline or validation errors // Recommend reinitialization of the component so that the user can try again // with different card data alert(`Declined: ${response.responseData.resultText}`); payabliReinit() break; default: // Other response text. These are normally errors with Payabli internal validations // before processor engagement // We recommend reinitializing the component. // If the problem persists, contact Payabli to help debug alert(`Error: ${response.responseText}`); payabliReinit() break; } }, functionCallBackError: (errors) => { // This callback covers 5XX response or parsing errors // We recommend reinitializing the component. // If the problem persists, contact Payabli to help debug console.log(errors); payabliReinit() } }, "pay", { paymentDetails: { totalAmount: 100, serviceFee: 0, categories: [ { label: "payment", amount: 100, qty: 1, }, ], }, }) return (
) } ```
### Types The hook receives the following arguments: The configuration object for the embedded component. See the [configuration reference](/guides/pay-in-components-embeddedmethod-ui#configuration-reference) for the component type you are using. The method to execute in `payabliExec`. See the [field](/guides/pay-in-components-overview#param-payabli-exec-action-parameters) for more information. An optional object that contains objects to pass to the `method`. See the [`paymentMethod`](/guides/pay-in-components-embeddedmethod-ui#param-payment-method), [`paymentDetails`](/guides/pay-in-components-embeddedmethod-ui#param-payment-details), or [`customerData`](/guides/pay-in-components-embeddedmethod-ui#param-customer-data) objects for more information. A boolean value that determines whether to use the production or sandbox environment. The hook returns an array with the following elements: The configuration object for the embedded component. See the [configuration reference](/guides/pay-in-components-embeddedmethod-ui#configuration-reference) for the component type you are using. A function to update the configuration object for the embedded component. This allows you to dynamically change the options after initialization. A function to execute the embedded component's method. This will call the method specified in the `method` argument passed to the hook. A function to reinitialize the embedded component. ## Vue Visit the [Vue integration example](https://github.com/payabli/examples/tree/main/vue-integration) 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: ```ts TypeScript // usePayabli.ts import { ref, reactive, onMounted, watchEffect } from 'vue'; const loadedScripts = new Set(); const useScript = (src: string) => { const isLoaded = ref(false); onMounted(() => { if (loadedScripts.has(src)) { isLoaded.value = true; return; } const existingScript = document.querySelector(`script[src="${src}"]`); const handleLoad = () => { loadedScripts.add(src); isLoaded.value = true; script.setAttribute("data-loaded", "true"); }; let script: HTMLScriptElement; if (!existingScript) { script = document.createElement("script"); script.src = src; script.async = true; script.addEventListener("load", handleLoad); document.body.appendChild(script); } else { if (existingScript.getAttribute("data-loaded") === "true") { isLoaded.value = true; } else { existingScript.addEventListener("load", handleLoad); } } }); return isLoaded; }; declare var PayabliComponent: any; export const usePayabli = ( options: any, method: string, parameters: any = null, production = false ) => { const payOptions = reactive({ ...options }); const isInitialized = ref(false); const payComponentRef = ref(null); const initCallbacks: (() => void)[] = []; const scriptSrc = production ? "https://embedded-component.payabli.com/component.js" : "https://embedded-component-sandbox.payabli.com/component.js"; const isScriptLoaded = useScript(scriptSrc); const initPayabli = () => { if (!isScriptLoaded.value || isInitialized.value) return; payComponentRef.value = new PayabliComponent(payOptions); isInitialized.value = true; initCallbacks.splice(0).forEach(cb => cb()); }; watchEffect(() => { if (isScriptLoaded.value) { initPayabli(); } }); watchEffect(() => { if (isInitialized.value && payComponentRef.value) { payComponentRef.value.updateConfig(payOptions); } }); const payabliReinit = () => { if (isInitialized.value && payComponentRef.value) { payComponentRef.value.payabliExec("reinit"); } }; const payabliExec = () => { const exec = () => { if (!payComponentRef.value) return; if (payOptions.type === "methodEmbedded") { if (parameters != null) { payComponentRef.value.payabliExec(method, parameters); } else { payComponentRef.value.payabliExec(method); } } else if ( payOptions.type === "methodLightbox" || payOptions.type === "vterminal" ) { payComponentRef.value.showModal(); } }; if (isInitialized.value) { exec(); } else { initCallbacks.push(exec); } }; return [payOptions, payabliExec, payabliReinit] as const; }; ``` ### 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 Vue ``` ### Types The composable receives the following arguments: The configuration object for the embedded component. See the [configuration reference](/guides/pay-in-components-embeddedmethod-ui#configuration-reference) for the component type you are using. The method to execute in `payabliExec`. See the [field](/guides/pay-in-components-overview#param-payabli-exec-action-parameters) for more information. An optional object that contains objects to pass to the `method`. See the [`paymentMethod`](/guides/pay-in-components-embeddedmethod-ui#param-payment-method), [`paymentDetails`](/guides/pay-in-components-embeddedmethod-ui#param-payment-details), or [`customerData`](/guides/pay-in-components-embeddedmethod-ui#param-customer-data) objects for more information. A boolean value that determines whether to use the production or sandbox environment. The composable returns an array with the following elements: The configuration object for the embedded component. See the [configuration reference](/guides/pay-in-components-embeddedmethod-ui#configuration-reference) for the component type you are using. A function to execute the embedded component's method. This will call the method specified in the `method` argument passed to the hook. A function to reinitialize the embedded component. ## Related resources See these related resources to help you get the most out of Payabli. * **[Embedded components overview](/guides/pay-in-components-overview)** - Learn how to use Payabli's embedded components to create customized checkout experiences without handling sensitive payment information yourself * **[EmbeddedMethod UI](/guides/pay-in-components-embeddedmethod-ui)** - Learn how to use the EmbeddedMethod UI embedded component to add the ability to securely store a payment profile or execute a sale