Inttegro for React
Use @inttegro/react to render Inttegro-hosted Checkout as a React component.
The adapter loads and mounts Checkout, applies supported updates, forwards
lifecycle events, and cleans up with the component tree.
Prerequisites
- React 18 or newer
- A backend that creates and finalizes an Inttegro Order
- A client-safe finalized Order ID or Purchase Intent ID
Install the component
- npm
- Yarn
- Bun
- Deno
npm install @inttegro/react
yarn add @inttegro/react
bun add @inttegro/react
deno add npm:@inttegro/react
Deno installs this package through its npm compatibility layer. When importing without an import map, prefix the package with npm:.
Choose and render a presentation
The Next.js live demo uses
@inttegro/react for both presentations while keeping Order creation on the
server; its released React entry point
shows the complete adapter boundary. Compare the presentations below, then use
the matching implementation that follows. Open any screenshot at full size when
you need to inspect the layout.
- Desktop
- Mobile
Select any image to view it full screen.
Both presentations use the same Checkout component and finalized Order. For
a modal, your application places that component inside its own accessible
dialog.
- Embedded
- Modal
Choose embedded Checkout for a dedicated payment route, checkout step, or invoice layout where the form should remain visible. React owns the component's position and surrounding content; Inttegro owns the hosted payment surface inside it.
'use client'
import { useState } from 'react'
import { Checkout } from '@inttegro/react'
function errorMessage(error: Error) {
return error.message
}
export function CheckoutPage({ orderId }: { orderId: string }) {
const [message, setMessage] = useState('')
return (
<main>
<h1>Complete your order</h1>
<section aria-label="Payment">
<Checkout
appearance={{ theme: 'system' }}
locale="en-GH"
orderId={orderId}
onCompleted={() => window.location.assign('/payment-status')}
onError={(error) => setMessage(errorMessage(error))}
/>
</section>
<p aria-live="polite">{message}</p>
</main>
)
}
Keep Checkout mounted while payment or provider confirmation is in progress.
You may style the outer
component with className or style, but merchant CSS does not reach the
hosted controls. Let Checkout report its own height; avoid fixed heights or
overflow clipping on the payment region.
Choose a modal when payment starts from a button and the current page should
remain mounted underneath. Your application owns the dialog, trigger, close
control, focus restoration, and scrolling. Mount the same Checkout component
inside the dialog only while it is open.
'use client'
import { useRef, useState } from 'react'
import { Checkout, type CheckoutHandle } from '@inttegro/react'
function errorMessage(error: Error) {
return error.message
}
export function PaymentAction({ orderId }: { orderId: string }) {
const checkout = useRef<CheckoutHandle>(null)
const dialog = useRef<HTMLDialogElement>(null)
const [open, setOpen] = useState(false)
const [message, setMessage] = useState('')
function openDialog() {
setOpen(true)
dialog.current?.showModal()
}
function handleError(error: Error) {
setMessage(errorMessage(error))
}
return (
<>
<button disabled={open} onClick={openDialog}>
Pay now
</button>
<dialog
ref={dialog}
aria-labelledby="payment-title"
onClose={() => setOpen(false)}
>
<h2 id="payment-title">Complete payment</h2>
<button type="button" onClick={() => dialog.current?.close()}>
Close
</button>
{open ? (
<Checkout
ref={checkout}
appearance={{ theme: 'system' }}
orderId={orderId}
onReady={() => checkout.current?.focus()}
onCompleted={() => window.location.assign('/payment-status')}
onError={handleError}
/>
) : null}
</dialog>
<p aria-live="polite">{message}</p>
</>
)
}
Closing the application dialog resets open; React then unmounts Checkout
and releases its controller and event subscriptions. Keep the dialog open while
a payment attempt or provider confirmation is in progress.
Start from a Buy link
Pass a Buy link's public Purchase Intent instead of creating a finalized Order:
<Checkout purchaseIntentId={purchaseIntentId} />
Use the same prop with presentation="modal" for the managed modal experience.
Checkout renders the full Buy experience and creates the finalized Order only
after the buyer continues. Payment then continues in the same component.
Provide either orderId or purchaseIntentId, never both.
The component also accepts features, timeout, and title. features
controls line-item visibility, post-payment invoice and receipt actions, and
whether an attached payment method can be replaced. Changing appearance or
locale updates the active Checkout. Changing features, orderId,
purchaseIntentId, timeout, or title creates a new instance.
Handle lifecycle callbacks
| Prop | Called when |
|---|---|
onCanceled | The payer leaves managed modal Checkout. |
onCompleted | Checkout reaches its successful terminal experience. |
onError | Loading or mounting fails before Checkout can continue. |
onEvent | Any privacy-safe lifecycle event is received. |
onFailed | Checkout reaches a terminal failure. |
onReady | Checkout is ready for customer interaction. |
onError receives an Error for loader or mount failures. onEvent receives
the canonical Checkout lifecycle, including recoverable
paymentAttemptFailed events and the terminal completed, canceled, and
failed events. Order-backed events carry the full client-safe Order.
Use these callbacks for interface state and telemetry. A completed callback is not fulfillment authority; have your backend look up the Order before releasing goods or granting access.
Focus or update Checkout
The forwarded ref exposes focus() and update():
import { useRef } from 'react'
import { Checkout, type CheckoutHandle } from '@inttegro/react'
export function FocusedCheckout({ orderId }: { orderId: string }) {
const checkout = useRef<CheckoutHandle>(null)
return (
<Checkout
ref={checkout}
orderId={orderId}
onReady={() => checkout.current?.focus()}
/>
)
}
Use update() only for appearance and locale. Passing those values as props
is preferable when they already belong to React state.
Use routes and server rendering
The adapter mounts Checkout in an effect, so it does not access the browser
during React's server render. In frameworks that distinguish Server and Client
Components, render Checkout from a Client Component. For example, add
'use client' to the component that imports @inttegro/react in the Next.js
App Router.
Related resources
- JavaScript runtime and loader - Review options, events, CSP, and modal behavior.
- Inertia - Use this component with an Inertia React frontend.
- Web Checkout overview - Prepare the server and verify payment state.