Last Updated: 19 September 2024 | Change Log

Shadow DOM


You can inject the SDK in a Shadow DOM, making sure that the encapsulation of your HTML code/custom elements is preserved. Both open and closed modes are supported.

Example configuration

To inject the SDK in a Shadow DOM, you must pass a reference to the shadowRoot of your Shadow DOM in the SDK configuration:

Worldpay.checkout.init(
  {
    id: "your-checkout-id",
    form: "#card-form",
    fields: {
      pan: {
        selector: "#card-pan",
        placeholder: "4444333322221111"
      },
      cvv: {
        selector: "#card-cvv",
        placeholder: "123"
      },
      expiry: {
        selector: "#card-expiry",
        placeholder: "MM/YY"
      }
    },
    shadowRoot: myShadowRoot // a reference to a shadow root is passed in the shadowRoot property
  },
  function (error, checkout) {
    if (error) {
      console.error(error);
      return;
    }
    
    // rest of your code run at the time where the SDK is initialized
  }
);

Integration with custom elements

You can also leverage the power of Shadow DOM to encapsulate all your checkout code in a custom element.

Here is a full example:

<script language="JavaScript">
  // Place the JavaScript code here
</script>

<template id="custom-checkout-template">
    <style>
        p {
            color: white;
            background-color: #666;
            padding: 5px;
        }

        body {
            font: 11px/22px sans-serif;
            text-transform: uppercase;
            background-color: #f7f7f7;
            color: black;
        }

        .container {
            height: 100vh;
            display: flex;
            justify-content: center;
            align-items: center;
        }

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

        .card .checkout .col-2 {
            display: flex;
        }

        .card .checkout .col-2 .col:first-child {
            margin-right: 15px;
        }

        .card .checkout .col-2 .col:last-child {
            margin-left: 15px;
        }

        .card .checkout .label .type {
            color: green;
        }

        .card .checkout.visa .label .type:before {
            content: "(visa)";
        }

        .card .checkout.mastercard .label .type:before {
            content: "(master card)";
        }

        .card .checkout.amex .label .type:before {
            content: "(american express)";
        }

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

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

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

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

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

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

        .card .checkout .submit {
            background: red;
            position: absolute;
            cursor: pointer;
            left: 50%;
            bottom: -60px;
            width: 200px;
            margin-left: -100px;
            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;
        }

        .card .checkout.is-valid .submit {
            background: green;
        }

        .clear {
            background: grey;
            position: absolute;
            cursor: pointer;
            left: 50%;
            bottom: -120px;
            width: 200px;
            margin-left: -100px;
            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;
        }
    </style>

    <section class="container">
        <section class="card">
            <form class="checkout" id="card-form">
                <div class="label">Card number <span class="type"></span></div>
                <section id="card-pan" class="field"></section>
                <section class="col-2">
                    <section class="col">
                        <div class="label">Expiry date</div>
                        <section id="card-expiry" class="field"></section>
                    </section>
                    <section class="col">
                        <div class="label">CVV</div>
                        <section id="card-cvv" class="field"></section>
                    </section>
                </section>
                <button class="submit" type="submit">Pay Now</button>
            </form>
            <button class="clear" id="clear">Clear</button>
        </section>
    </section>
</template>

<script src="https://try.access.worldpay.com/access-checkout/v2/checkout.js" onload="addCheckout()"></script>

// For production change to "https://access.worldpay.com/access-checkout/v2/checkout.js"

Limitations

The SDK is not compatible with nested Shadow DOMs. It can only be initialized in a Shadow DOM when the host belongs to the main document DOM.