Inttegro Web SDKs - v0.5.3
    Preparing search index...

    Integrate Checkout with Vue

    Vue combines declarative templates with reactive props, lifecycle hooks, and explicit component events. @inttegro/vue presents Inttegro Checkout in those terms: reactive presentation props update the hosted experience, identity props replace it, and lifecycle events are emitted through Vue's normal @event syntax.

    Use the official adapter for Vue 3.4 or later. It keeps the imperative hosted controller behind a declarative component, cancels stale asynchronous mounts during rapid navigation, and exposes only the two imperative operations that are useful to a parent component. That is safer and easier to review than duplicating loader, watcher, subscription, and teardown code in every payment view.

    Use your application's existing package manager. With npm:

    npm install @inttegro/vue
    

    @inttegro/vue depends on @inttegro/js, whose loader downloads the executable runtime from Inttegro's fixed origin. Neither package contains a copy of the sensitive payment-collection runtime.

    Create and finalize the Order on your server, then pass only its client-safe Order ID to the Vue page. Secret Inttegro credentials must never enter defineProps, Nuxt payload state, or browser environment variables.

    This Vue component forwards the complete event stream to application telemetry, routes after completion, and renders a fallback only when Checkout itself could not initialize:

    <script setup lang="ts">
    import { ref } from 'vue'
    import { useRouter } from 'vue-router'
    import { Checkout, type CheckoutEvent } from '@inttegro/vue'

    const props = defineProps<{
    orderId: string
    pageSessionId: string
    }>()

    const router = useRouter()
    const initializationFailed = ref(false)
    const paymentFailed = ref(false)

    function recordEvent(event: CheckoutEvent) {
    navigator.sendBeacon(
    '/telemetry/checkout',
    new Blob(
    [
    JSON.stringify({
    type: event.type,
    occurredAt: event.occurredAt,
    pageSessionId: props.pageSessionId,
    }),
    ],
    { type: 'application/json' },
    ),
    )
    }

    function handleError(error: Error) {
    initializationFailed.value = true
    navigator.sendBeacon(
    '/telemetry/checkout',
    new Blob(
    [
    JSON.stringify({
    type: 'initializationFailed',
    message: error.message,
    pageSessionId: props.pageSessionId,
    }),
    ],
    { type: 'application/json' },
    ),
    )
    }

    function handleFailed() {
    paymentFailed.value = true
    }

    function handleCompleted() {
    void router.push('/orders/complete')
    }
    </script>

    <template>
    <main>
    <h1>Complete your order</h1>
    <p v-if="initializationFailed" role="alert">
    Checkout could not load. Refresh the page to try again.
    </p>
    <p v-else-if="paymentFailed" role="alert">
    Payment could not be completed. Try again or choose another payment
    method.
    </p>
    <Checkout
    v-show="!initializationFailed && !paymentFailed"
    :order-id="props.orderId"
    :appearance="{ theme: 'system' }"
    locale="en-GH"
    title="Payment for your order"
    style="inline-size: 100%; min-block-size: 32rem"
    @event="recordEvent"
    @completed="handleCompleted"
    @failed="handleFailed"
    @error="handleError"
    />
    </main>
    </template>

    The completion route must reconcile the Order from your server before fulfillment. Vue navigation follows the browser event; it does not turn that event into server-authoritative payment state.

    The adapter uses Vue primitives intentionally:

    • onMounted starts browser runtime loading and mounts the controller into the component's div.
    • A watcher on appearance and locale calls update() on the active controller. The watcher is deep, so a nested theme change is observed.
    • A watcher on features, orderId, presentation, timeout, and title destroys the controller and starts a new embedded or modal experience because those values identify its lifecycle.
    • onBeforeUnmount unsubscribes from events and destroys the controller.
    • A generation counter invalidates an older asynchronous load when props change or the view unmounts before loading completes.

    This makes the component predictable inside v-if, <RouterView>, and transitions: the Vue view that renders Checkout owns exactly one current controller. With presentation="modal", the shared runtime owns the dialog itself. Keep the component mounted while payment submission or provider confirmation is pending. Removing it destroys the frame even if the server-side attempt continues.

    The component uses Vue emits rather than DOM custom events. It emits event, ready, completed, canceled, failed, and error. Set presentation="modal" to delegate the dialog, backdrop, viewport scrolling, close control, and focus behavior to Inttegro:

    <script setup lang="ts">
    import { ref } from 'vue'
    import { Checkout } from '@inttegro/vue'

    const open = ref(false)
    </script>

    <template>
    <button @click="open = true">Pay now</button>
    <Checkout
    v-if="open"
    :order-id="orderId"
    presentation="modal"
    @canceled="open = false"
    />
    </template>

    The CheckoutExposed template-ref interface provides dismiss(), focus(), and update(). Prefer reactive props for ordinary application state. Use dismiss() only when host state must close the managed modal programmatically.

    The event emission receives every sanitized CheckoutEvent. It is the reliable integration point for lifecycle states without a dedicated emission, such as paymentActionRequired, paymentProcessing, and paymentAttemptFailed. Use the dedicated canceled emission to update the state that conditionally renders modal Checkout.

    The failed emission receives Checkout's sanitized terminal failure event. The error emission receives a JavaScript Error only when runtime loading or mounting fails. Do not replace Checkout for a recoverable paymentAttemptFailed event; the frame owns its retry and correction UI.

    The adapter renders only its empty container during server rendering. Runtime loading starts in onMounted, after the component is in the browser, so Nuxt and other Vue SSR applications can render and hydrate the same initial structure.

    Pass the Order ID through server-owned page data, but do not render secret credentials into the hydration payload. If route data changes to another Order ID, expect a fresh Checkout by design. A locale or theme change updates the current one instead.

    The current adapter does not expose loadInttegro() options. If a strict Content Security Policy requires a per-response nonce on the runtime script or managed-modal stylesheet, integrate with @inttegro/js directly. For normal Vue-owned routes and managed modals, the official adapter remains the preferred lifecycle boundary.