**Last updated**: 31 March 2026 | [**Change log**](/access/products/checkout/web/changelog/)

# React integration

Integrate the Access Checkout Web SDK in a React application.

## Integration

1. You must add the SDK `checkout.js` script to your app html code and make sure this is done **only once**.
To do this, you may want to add it in your main application or add it dynamically as part of one of your components.
2. Before initializing the SDK, you must load the `checkout.js` script successfully.
The reason is that this script creates an object on the `window` object which is required by the initialization mechanism.
3. You must call the SDK's `remove()` method **only once** as part of your component unmounting phase but when the DOM is still available.
You can do this by using the `useLayoutEffect` hook and by calling the `remove()` method in the cleanup function run by the hook.


### Full integration example

JavaScript

```javascript
import React, {useEffect, useLayoutEffect} from "react";
import "./CheckoutIntegrationSample.css";

function scriptAlreadyLoaded(src) {
  return document.querySelector(`script[src="${src}"]`);
}

function loadCheckoutScript(src) {
  return new Promise((resolve, reject) => {
    if (scriptAlreadyLoaded(src)) {
      resolve();
      return;
    }

    let checkoutScript = document.createElement("script");
    checkoutScript.src = src;
    checkoutScript.onload = resolve;
    checkoutScript.onerror = reject;
    document.head.appendChild(checkoutScript);
  });
}

function addWorldpayCheckoutToPage() {
  return new Promise((resolve, reject) => {
    (function () {
      window.Worldpay.checkout.init(
        {
          id: "your-checkout-id",
          form: "#container",
          fields: {
            pan: {
              selector: "#card-pan",
            },
            expiry: {
              selector: "#card-expiry",
            },
            cvv: {
              selector: "#card-cvv",
            },
          },
          styles: {
            "input.is-valid": {
              "color": "green",
            },
            "input.is-invalid": {
              "color": "red",
            },
            "input.is-onfocus": {
              "color": "black",
            },
          },
          enablePanFormatting: true,
          allowNonLuhnCompliantCards: true,
        },
        function (error, checkout) {
          if (error) {
            reject(error);
          } else {
            resolve(checkout);
          }
        },
      );
    })();
  });
}

function CheckoutIntegrationSample() {
  const checkoutScriptUrl = "https://try.access.worldpay.com/access-checkout/v2/checkout.js";
  let checkout;

  function generateSession () {
    checkout.generateSessionState(
      function (error, session) {
        if (error) {
          console.warn(`Failed to generate session: ${error}`);
          return;
        }

        const infoDiv = document.querySelector(".info");
        infoDiv.innerHTML += `<div>Session retrieved is ${session}</div>`;
      });
  }

  function clearForm () {
    checkout.clearForm(() => {
      document.querySelector(".info").innerHTML = "";
    });
  }

  useEffect(() => {
    loadCheckoutScript(checkoutScriptUrl)
      .then(() => {
        addWorldpayCheckoutToPage()
          .then((checkoutInstance) => {
            checkout = checkoutInstance;
          })
          .catch(console.warn);
      })
      .catch(console.warn);
  }, []);

  useLayoutEffect(() => {
    // Make sure to call the remove method (once) in order to deallocate the SDK from memory
    return () => checkout.remove();
  },
    []);

  return (
    <section className="container" id="container">
      <section className="card">
        <section id="card-pan" className="field" />
        <section className="columns">
        <section>
        <section id="card-expiry" className="field" />
        </section>
        <section>
        <section id="card-cvv" className="field" />
        </section>
        </section>
        <section className="buttons">
          <button className="submit" type="button" onClick={generateSession}>
            Generate Session
          </button>
          <button className="clear" type="button" onClick={clearForm}>
            Clear
          </button>
        </section>
      </section>
      <div id="info" className="info" />
    </section>
  );
}

export default CheckoutIntegrationSample;
```

CSS

```css
.container {
  display: flex;
  align-items: center;
  flex-direction: column;
}

.card {
  background: white;
  padding: 20px 30px;
  top: -30px;
  width: 100%;
  max-width: 300px;
  border-radius: 12px;
  box-shadow: 3px 3px 60px 0px rgba(0, 0, 0, 0.1);
}

.columns {
  display: flex;
}

.columns > * {
  margin-right: 15px;
}

.field {
  height: 40px;
  border-bottom: 1px solid lightgray;
}

.field.is-onfocus {
  border-color: black;
}

.field.is-empty {
  border-color: orange;
}

.field.is-invalid {
  border-color: red;
}

.field.is-valid {
  border-color: green;
}

#card-pan {
  margin-bottom: 30px;
}

.submit {
  background: green;
  cursor: pointer;
  width: 200px;
  margin-top:30px;
  color: white;
  outline: 0;
  font-size: 14px;
  border: 0;
  border-radius: 30px;
  text-transform: uppercase;
  font-weight: bold;
  padding: 15px 0;
  transition: background 0.3s ease;
  margin-right:20px;
}

.clear {
  background: green;
  cursor: pointer;
  width: 100px;
  margin-top:30px;
  color: white;
  outline: 0;
  font-size: 14px;
  border: 0;
  border-radius: 30px;
  text-transform: uppercase;
  font-weight: bold;
  padding: 15px 0;
  transition: background 0.3s ease;
}

.buttons {
  display: flex;
}

.info {
  width: 600px;
  word-wrap:break-word;
  margin-top: 20px;
  color: green;
}
```