---
title: "React"
description: "Integrate Inttegro Checkout as embedded content or inside an application-owned dialog in React."
canonical: "https://studio.inttegro.com/web/react"
format: inttegro-machine-docs/v1
language: "TypeScript"
sdk_version: "v12.0.0"
reader_profile: optional
reader_manifest: "https://studio.inttegro.com/machine/typescript/readers/index.json"
reader_identification: "Optional: declare your client only if known and your current-session capabilities; use reader_manifest for supplemental recommendations."
preamble_estimated_tokens: 609
model_token_report: "https://studio.inttegro.com/machine/token-report.json"
preamble_questions: 5
preamble_source: "curated"
recommended_mcp_tools: ["design_integration","check_integration_readiness"]
estimated_tokens: 2813
token_estimate_method: "utf8_bytes_divided_by_4"
---

## Machine preamble

**Summary:** Use the React component only after a trusted backend finalizes the order; lifecycle callbacks drive UI, while server lookup establishes the payment outcome.

### Five questions

#### Q1. What must the React page receive from its backend?

Only the finalized Order ID needed by Checkout. Keep API credentials, customer payment details, and decisions about line items and amount in the trusted backend; [Orders](https://studio.inttegro.com/machine/typescript/api/orders.md#create-an-order) defines creation and [web setup](https://studio.inttegro.com/machine/typescript/web.md) describes the handoff.

#### Q2. Which package and presentation does React use?

Install @inttegro/react and render its documented Checkout component for embedded or modal presentation; a hosted-page handoff does not mount the component. Choose one path in [the React guide](https://studio.inttegro.com/machine/typescript/web/react.md#choose-and-render-a-presentation) before wiring lifecycle events.

#### Q3. What does the completed event mean?

Use onCompleted for UI or navigation, then ask the backend to [look up the Order](https://studio.inttegro.com/machine/typescript/api/orders.md#lookup-an-order) before fulfillment. Handle the documented error and other lifecycle signals separately; [events](https://studio.inttegro.com/machine/typescript/web/react.md#handle-lifecycle-callbacks) are not a replacement for server state.

#### Q4. How do updates and server rendering affect Checkout?

A changed Order ID, features, timeout, or title creates a new Checkout instance; supported appearance/locale changes can update an active one. The adapter mounts in an effect; mark the wrapper as a Client component when the framework separates server and client rendering. See [routes and server rendering](https://studio.inttegro.com/machine/typescript/web/react.md#use-routes-and-server-rendering).

#### Q5. What can an integration agent verify first?

With an authenticated MCP connection, [design_integration](https://studio.inttegro.com/machine/typescript/inttegro-mcp/tools.md#design_integration) can plan the backend/browser boundary and [check_integration_readiness](https://studio.inttegro.com/machine/typescript/inttegro-mcp/tools.md#check_integration_readiness) can audit declared secret, idempotency, and lookup controls. Compile the React example and test success, cancellation, and failure with disposable orders.

## Document content

# 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](https://studio.inttegro.com/machine/typescript/api/orders.md#create-an-order) and
  [finalizes](https://studio.inttegro.com/machine/typescript/api/orders.md#finalize-an-order) an Inttegro Order
- A client-safe finalized Order ID or Purchase Intent ID

## Install the component

> Web Sdk Install Tabs is interactive content. Use the canonical page to view it.

## Choose and render a presentation

The [Next.js live demo](https://nextjs-demo.inttegro.dev) uses
`@inttegro/react` for both presentations while keeping Order creation on the
server; its [released React entry point](https://github.com/inttegro/inttegro-demos/blob/nextjs-v1.8.3/nextjs/app/inttegro-demo-checkout.tsx)
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.

> Demo Presentation Gallery is interactive content. Use the canonical page to view it.

Both presentations use the same `Checkout` component and finalized Order. For
a modal, your application places that component inside its own accessible
dialog.

### Embedded

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.

```tsx
'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.

### Modal

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.

```tsx
'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:

```tsx
<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](https://studio.inttegro.com/machine/typescript/api/orders.md#lookup-an-order) before releasing goods or granting access.

## Focus or update Checkout

The forwarded ref exposes `focus()` and `update()`:

```tsx
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](https://studio.inttegro.com/machine/typescript/web/javascript.md) - Review options, events,
  CSP, and modal behavior.
- [Inertia](https://studio.inttegro.com/machine/typescript/web/inertia.md) - Use this component with an Inertia React frontend.
- [Web Checkout overview](https://studio.inttegro.com/machine/typescript/web.md) - Prepare the server and verify payment state.
