# Implementing a Components checkout

[Components](https://docs.digitalriver.com/digital-river-api/developer-resources/digitalrivercheckout.js-reference/digitalrivercheckout-object/components) are a [low-code checkout option](https://docs.digitalriver.com/digital-river-api/integration-options/low-code-checkouts) that consists of UI building blocks. They allow you to create customized checkout flows that connect to Digital River's address validation, [local pricing](https://docs.digitalriver.com/digital-river-api/using-our-services/local-pricing), [payment processing](https://docs.digitalriver.com/digital-river-api/payments/payment-integrations-1), [subscription](https://docs.digitalriver.com/digital-river-api/using-our-services/subscriptions), fraud detection, tax computation, and compliance services.

[Components](https://docs.digitalriver.com/digital-river-api/developer-resources/digitalrivercheckout.js-reference/digitalrivercheckout-object/components) make it even easier to integrate with Digital River, reducing the time spent launching and managing your solution.

You can use all [available components](https://docs.digitalriver.com/digital-river-api/developer-resources/digitalrivercheckout.js-reference/digitalrivercheckout-object/components#supported-component-types) to create traditional checkout flows. Alternatively, you might decide to use them selectively to construct specialized flows. For example, by pairing the [wallet component](https://docs.digitalriver.com/digital-river-api/developer-resources/digitalrivercheckout.js-reference/digitalrivercheckout-object/components/wallet-component) with the [compliance component](https://docs.digitalriver.com/digital-river-api/developer-resources/digitalrivercheckout.js-reference/digitalrivercheckout-object/components/compliance-component), you can offer customers an expedited checkout experience.

On this page, you'll find information on:

* [Building a cart and initiating checkout](#building-a-cart-and-initiating-checkout)
* [Designing the checkout experience](#designing-the-checkout-experience)
* [Executing a components checkout](#executing-a-components-checkout)
* [Handling front-end events](#handling-front-end-events)
* [Controlling the flow of the checkout](#controlling-the-checkout-flow)
* [Submitting data collected by components](#submitting-components)

After customers complete the checkout process, your application must also [handle completed checkout-sessions](https://docs.digitalriver.com/digital-river-api/integration-options/low-code-checkouts/handling-completed-checkout-sessions).

## Building a cart and initiating checkout

During the early stages of an eCommerce transaction, customers land on your storefront, review products, and build a cart. Digital River is typically not involved in these pre-checkout interactions unless you're engaging our [local pricing service](https://docs.digitalriver.com/digital-river-api/using-our-services/local-pricing). However, once customers initiate checkout, you must start interacting with [components](https://docs.digitalriver.com/digital-river-api/developer-resources/digitalrivercheckout.js-reference/digitalrivercheckout-object/components).

## Designing the checkout experience

For each component you implement, your DOM needs to contain a unique HTML element to display it.

```html
...
<div id="address-container" style="display: block"></div>
<div id="shipping-container" style="display: block"></div>
<div id="tax-identifier-container" style="display: block"></div>
<div id="payment-container" style="display: block"></div>
<div id="wallet-container" style="display: block"></div>
<div id="compliance-container" style="display: block"></div>
<div id="order-summary-container" style="display: block"></div>
<div>
    <div>
        <button id="previousButton" onclick="onPreviousButtonClick()">Previous</button>
    </div>
    <div>
        <button id="nextButton" onclick="onNextButtonClick()">Next</button>
    </div>
</div>
<div id="order-confirmation-container" style="display: none"></div>
...

```

The following example uses all of the [available components](https://docs.digitalriver.com/digital-river-api/developer-resources/digitalrivercheckout.js-reference/digitalrivercheckout-object/components#supported-component-types), but how you design your experience is highly customizable.

{% tabs %}
{% tab title="Address collection stage" %}

<div align="left"><figure><img src="https://334437993-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-LqH4RJfLVLuHPXuJyTZ%2Fuploads%2FlhVhIPriQyzTZXImdKYU%2FAddress%20collection%20stage%20-%20web.png?alt=media&#x26;token=e57f0c28-720d-4938-993c-a9853a2870a3" alt=""><figcaption></figcaption></figure></div>
{% endtab %}

{% tab title="Shipping choice collection stage" %}

<div align="left"><figure><img src="https://334437993-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-LqH4RJfLVLuHPXuJyTZ%2Fuploads%2FompimO3RVZYAkWzTNcw9%2FShipping%20choice%20collection%20stage%20-%20web.png?alt=media&#x26;token=2b1696f1-cd30-42ad-bad1-7081ec37a352" alt=""><figcaption></figcaption></figure></div>
{% endtab %}

{% tab title="Tax identifier collection stage" %}

<div align="left"><figure><img src="https://334437993-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-LqH4RJfLVLuHPXuJyTZ%2Fuploads%2FvDGPXpniOuQOi40s67la%2FTax%20id%20collection%20stage.jpg?alt=media&#x26;token=67a6df40-10f2-4e4d-a945-7edea4a4afbb" alt=""><figcaption></figcaption></figure></div>
{% endtab %}

{% tab title="e-invoice collection stage" %}

<div align="left"><figure><img src="https://334437993-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-LqH4RJfLVLuHPXuJyTZ%2Fuploads%2FVsSkT1Ovo7XbG6b8Z5kH%2FInvoice%20collection%20stage.png?alt=media&#x26;token=fe4f4847-c36b-4e05-9a9c-ec26cbc67128" alt=""><figcaption></figcaption></figure></div>
{% endtab %}

{% tab title="Payment collection stage" %}

<div align="left"><figure><img src="https://334437993-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-LqH4RJfLVLuHPXuJyTZ%2Fuploads%2FHcB2YuWV2x43q5sVp3ak%2FPayment%20collection%20stage%20-%20web.jpg?alt=media&#x26;token=b8b777be-62ee-44e8-aac5-a07c4cb11dab" alt=""><figcaption></figcaption></figure></div>
{% endtab %}

{% tab title="Order confirmation stage" %}

<div align="left"><img src="https://334437993-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-LqH4RJfLVLuHPXuJyTZ%2Fuploads%2F9tXk2HjFuDo6Pn26zMmA%2FThank%20you%20stage%20-%20web.png?alt=media&#x26;token=4245c285-4067-466d-abc9-468bd6a87389" alt=""></div>
{% endtab %}
{% endtabs %}

<div align="left"><figure><img src="https://334437993-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-LqH4RJfLVLuHPXuJyTZ%2Fuploads%2F2gbLSHH4FaTSWdRmChcq%2FKey.png?alt=media&#x26;token=d9979333-8400-4bd4-9694-6dc54f4b708a" alt="" width="375"><figcaption></figcaption></figure></div>

If you implement multiple components that accept customer input, such as [address](https://docs.digitalriver.com/digital-river-api/developer-resources/digitalrivercheckout.js-reference/digitalrivercheckout-object/components/address-component), [shipping](https://docs.digitalriver.com/digital-river-api/developer-resources/digitalrivercheckout.js-reference/digitalrivercheckout-object/components/shipping-component), and [payment](https://docs.digitalriver.com/digital-river-api/developer-resources/digitalrivercheckout.js-reference/digitalrivercheckout-object/components/payment-component), your experience should also contain buttons or some other type of navigational control that allows customers to move the checkout process forward and backward. These button-click events should activate your [checkout flow control](#controlling-the-checkout-flow) functionality.

## Executing a components checkout

On your checkout page, you should:

* [Add the necessary scripts and style sheets](#add-scripts-and-style-sheets)
* [Create a Digital River Checkout object](#create-a-digital-river-checkout-object)
* [Invoke a custom-built function that initializes components](#initialize-components)

### Add scripts and style sheets

In the `head` of your `html`, [add the DigitalRiverCheckout.js](https://docs.digitalriver.com/digital-river-api/developer-resources/digitalrivercheckout.js-reference/including-digitalrivercheckout.js) script. If you'd like, you can also include a `link` to the `DigitalRiver.css` style sheet.

```html
<head>
    <title>Checkout Page</title>
    <script defer="defer" src="https://checkout.digitalriverws.com/v1/DigitalRiverCheckout.js"></script>
    <link rel="stylesheet" href="https://js.digitalriverws.com/v1/css/DigitalRiver.css" type="text/css"/>
</head>
```

### Create a Digital River Checkout object

Use your [public API key](https://docs.digitalriver.com/digital-river-api/administration/dashboard/developers/api-keys) to [create a `DigitalCheckoutRiver` object](https://docs.digitalriver.com/digital-river-api/developer-resources/digitalrivercheckout.js-reference/initializing-digitalrivercheckout.js).

```javascript
let digitalRiverCheckout = new DigitalRiverCheckout("YOUR_PUBLIC_API_KEY");
```

### Initialize components

When your checkout page loads, invoke an asynchronous function that initializes components.

```javascript
...
initializeComponents();
...
```

The [async function](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function) you implement should:

* [Build a `components()` configuration object](#build-a-configuration-object)
* [Pass that object to `components()`](#create-the-components-object)
* [Create each individual component that you want to use](#create-individual-components)
* [Mount each of those components](#mount-individual-components)

```javascript
async function initializeComponents() {
    //Build a configuration object
    const configuration = {
        checkoutSessionId: await createComponentsCheckoutSession(),
        onReady: function (data) {
            //Handle event
        },
        onChange: function (data) {
            //Handle event
        },
        onSuccess: function (data) {
            //Handle event
        }
    }
    //Create components
    let components;
    components = digitalRiverCheckout.components(configuration);
    
    //Create the individual components
    paymentComponent = components.createComponent('payment');
    shippingComponent = components.createComponent('shipping');
    addressComponent = components.createComponent('address');
    walletComponent = components.createComponent('wallet');
    thankYouComponent = components.createComponent('thankyou');
    complianceComponent = components.createComponent('compliance');
    orderSummaryComponent = components.createComponent('ordersummary');
    
    //Mount the individual components
    paymentComponent.mount('payment-container');
    shippingComponent.mount('shipping-container');
    addressComponent.mount('address-container');
    walletComponent.mount('wallet-container');
    thankYouComponent.mount('order-confirmation-container');
    complianceComponent.mount('compliance-container');
    orderSummaryComponent.mount('order-summary-container');
}
```

#### Build a configuration object

To set `checkoutSessionId` in the [components configuration object](https://docs.digitalriver.com/digital-river-api/developer-resources/digitalrivercheckout.js-reference/digitalrivercheckout-object/components/configuring-components), you should invoke an asynchronous function, wrapped by your [initialize components function](#initialize-components), that defines a [checkout-session](https://app.gitbook.com/s/x8fSFzVR3sg0TsNWwwVz/drop-in-checkout-sessions/checkout-sessions-basics) on your front end and then passes that data to your server so that it can [submit the create request](https://app.gitbook.com/s/x8fSFzVR3sg0TsNWwwVz/drop-in-checkout-sessions#drop-in-checkout-sessions).

Alternatively, before loading your checkout page, you could define and create a [checkout-session](https://app.gitbook.com/s/x8fSFzVR3sg0TsNWwwVz/drop-in-checkout-sessions/checkout-sessions-basics) completely server-side.

In either case, the function you implement needs to return the checkout-session's `id`.

```javascript
function createComponentsCheckoutSession() {
  //Creates checkout-session
  //Returns checkout-session identifier
}
```

In the configuration object, you'll also need to define how you want to [handle callback methods](#handling-front-end-events).

```javascript
async function initializeComponents() {
    //Build a configuration object
    const configuration = {
        checkoutSessionId: await createComponentsCheckoutSession(),
        onReady: function (data) {
            //Handle event
        },
        onChange: function (data) {
            //Handle event
        },
        onSuccess: function (data) {
            //Handle event
        }
    }
    ...
}
```

#### Create the components object

Pass your [configuration object](https://docs.digitalriver.com/digital-river-api/developer-resources/digitalrivercheckout.js-reference/digitalrivercheckout-object/components/configuring-components) to [`components()`](https://docs.digitalriver.com/digital-river-api/developer-resources/digitalrivercheckout.js-reference/digitalrivercheckout-object/components#creating-components).

```javascript
async function initializeComponents() {
    ...
    //Create components
    let components;
    components = digitalRiverCheckout.components(configuration);
    ...
}
```

#### Create individual components

Use the object returned by `components()` to [create the individual components](https://docs.digitalriver.com/digital-river-api/developer-resources/digitalrivercheckout.js-reference/digitalrivercheckout-object/components#createcomponent-componenttype) that you want customers to interact with.

```javascript
async function initializeComponents() {
    ...
    //Create the individual components
    paymentComponent = components.createComponent('payment');
    shippingComponent = components.createComponent('shipping');
    addressComponent = components.createComponent('address');
    walletComponent = components.createComponent('wallet');
    thankYouComponent = components.createComponent('thankyou');
    complianceComponent = components.createComponent('compliance');
    orderSummaryComponent = components.createComponent('ordersummary');
    ...
}
```

#### Mount individual components

For each component, pass the `id` of its HTML container to [`mount()`](https://docs.digitalriver.com/digital-river-api/developer-resources/digitalrivercheckout.js-reference/digitalrivercheckout-object/components#mount-elementid).

```javascript
async function initializeComponents() {
    ...
    //Mount the individual components
    paymentComponent.mount('payment-container');
    shippingComponent.mount('shipping-container');
    addressComponent.mount('address-container');
    walletComponent.mount('wallet-container');
    thankYouComponent.mount('order-confirmation-container');
    complianceComponent.mount('compliance-container');
    orderSummaryComponent.mount('order-summary-container');
}
```

## Handling front-end events

Ensure you define how you'd like to handle the [ready](#ready-events), [change](#change-events), and [success](#success-events) callback functions.

### Ready events

Some of the ways you might handle [`onReady`](https://docs.digitalriver.com/digital-river-api/developer-resources/digitalrivercheckout.js-reference/digitalrivercheckout-object/components/configuring-components#onready) is by:

* Using [`data.requiresShipping`](https://docs.digitalriver.com/digital-river-api/developer-resources/digitalrivercheckout.js-reference/digitalrivercheckout-object/components/configuring-components#requiresshipping) to set a boolean variable that controls whether the [shipping component](#shipping-component) needs to be displayed during the checkout process.
* Using [`data.showTaxIdentifiers`](https://docs.digitalriver.com/digital-river-api/developer-resources/digitalrivercheckout.js-reference/digitalrivercheckout-object/components/configuring-components#showtaxidentifiers) to set a boolean that controls whether the [tax identifier component](https://docs.digitalriver.com/digital-river-api/developer-resources/digitalrivercheckout.js-reference/digitalrivercheckout-object/components/tax-identifier-component) needs to be displayed.
* Calling a function that [controls the flow of the checkout experience](#controlling-the-checkout-flow).

```javascript
...
onReady: function (data) {
  if (data.requiresShipping === false) { 
    //Update the variable that controls whether to display the shipping component
  }
  if (data.showTaxIdentifiers === false) {
    //Update the variable that controls whether to display the tax identifier component
  }
  //Call a function that determines the correct component(s) to display
},
...
```

### Change events

If you're using the [tax identifier component](https://docs.digitalriver.com/digital-river-api/developer-resources/digitalrivercheckout.js-reference/digitalrivercheckout-object/components/tax-identifier-component), handle [`onChange`](https://docs.digitalriver.com/digital-river-api/developer-resources/digitalrivercheckout.js-reference/digitalrivercheckout-object/components/configuring-components#onchange) by determining whether `optionalTaxIdentifiers[]` or `requiredTaxIdentifiers[]` exists in the returned `data`. If either does, set a variable that controls whether that component is displayed during checkout.

```javascript
onChange: function (data) {
    ...
    if (('optionalTaxIdentifiers' in data) || ('requiredTaxIdentifiers' in data)){
      //Set a display tax identifier component boolean variable to true
      //At some point in the checkout process, display the tax identifier component
    };
},
...
```

If, for whatever reason, you decide not to use the [order summary component](https://docs.digitalriver.com/digital-river-api/developer-resources/digitalrivercheckout.js-reference/digitalrivercheckout-object/components/order-summary-component), you can also use [`onChange`](https://docs.digitalriver.com/digital-river-api/developer-resources/digitalrivercheckout.js-reference/digitalrivercheckout-object/components/configuring-components#onchange) to update your custom-built order summary section. There are a variety of ways to do this.

The example below retrieves `locale`, `currency`, `totalAmount`, `totalShipping`, `totalTax`, and `subTotal`, along with each `items[].amount`, from the `data` returned by `onChange` and then constructs [JavaScript Int.NumberFormat](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/NumberFormat) objects which are then used to set the `innerText` of the appropriate HTML element.

In this example, the `sku.image` and `sku.name` of each `items[]` is also displayed.

```javascript
  ...
  onChange: function (data) {
    const locale = data.locale.replace('_', '-');
    document.getElementById('total').innerText =  new Intl.NumberFormat(locale, { style: 'currency', currency: data.currency }).format(data.totalAmount);
    document.getElementById('shipping').innerText =  new Intl.NumberFormat(locale, { style: 'currency', currency: data.currency }).format(data.totalShipping);
    document.getElementById('tax').innerText =  new Intl.NumberFormat(locale, { style: 'currency', currency: data.currency }).format(data.totalTax);
    document.getElementById('subtotal').innerText =  new Intl.NumberFormat(locale, { style: 'currency', currency: data.currency }).format(data.subtotal);
    document.getElementById('items').innerHTML = data.items.map( i => {
      return <div>
        <img style="height: 30px; width: 30px" src="${i.sku.image}"/> ${i.sku.name} - ${new Intl.NumberFormat(locale, { style: 'currency', currency: data.currency }).format(i.amount)}
      </div>
    });
  },
  ...
```

### Success events

One way to handle [`onSuccess`](https://docs.digitalriver.com/digital-river-api/developer-resources/digitalrivercheckout.js-reference/digitalrivercheckout-object/components/configuring-components#onsuccess) is by passing an argument to your [control checkout flow function](#controlling-the-checkout-flow), instructing it to display the [thank you component](https://docs.digitalriver.com/digital-river-api/developer-resources/digitalrivercheckout.js-reference/digitalrivercheckout-object/components/thank-you-component).

Alternatively, you could retrieve `order.id` (and whatever else you need) from `data` and use it to build your custom order confirmation page.

```javascript
  ...
  onSuccess: function (data) {
    // Display the thank you component or a customized order confirmation page
  },
  ...
```

## Controlling the checkout flow

To control the flow of the checkout experience, you'll need to implement asynchronous functionality.

One possible approach is to define a function that checks a position enumeration, each value of which corresponds to a stage in the checkout process, and then, depending on the value, uses [`document`](https://developer.mozilla.org/en-US/docs/Web/API/Document) to access each HTML element in your experience that holds a component, displaying and hiding the appropriate ones.

As you progress through the various checkout stages, make sure you also call `done()` to ensure the customer's inputs are submitted and valid. For details, refer to [Submitting components](#submitting-components).

## Submitting components

Some of the [available components](https://docs.digitalriver.com/digital-river-api/developer-resources/digitalrivercheckout.js-reference/digitalrivercheckout-object/components#supported-component-types) collect data from customers. Digital River handles submitting that data for a subset of these, but you must initiate the process for others.

For example, in the [payment component](https://docs.digitalriver.com/digital-river-api/developer-resources/digitalrivercheckout.js-reference/digitalrivercheckout-object/components/payment-component), DigitalRiver.js handles the button click event by sending a create [source](https://docs.digitalriver.com/digital-river-api/payments/payment-sources) request, performing any required [SCA](https://docs.digitalriver.com/digital-river-api/payments/psd2-and-sca) or redirects to the payment provider, and then, assuming those processes are successful, requesting that the payment object be added to the [checkout-session's](https://app.gitbook.com/s/x8fSFzVR3sg0TsNWwwVz/drop-in-checkout-sessions) `sources[]`.

On the other hand, the [address](https://docs.digitalriver.com/digital-river-api/developer-resources/digitalrivercheckout.js-reference/digitalrivercheckout-object/components/address-component), [shipping](https://docs.digitalriver.com/digital-river-api/developer-resources/digitalrivercheckout.js-reference/digitalrivercheckout-object/components/shipping-component), [tax identifier](https://docs.digitalriver.com/digital-river-api/developer-resources/digitalrivercheckout.js-reference/digitalrivercheckout-object/components/tax-identifier-component), and [invoice ](https://docs.digitalriver.com/digital-river-api/developer-resources/digitalrivercheckout.js-reference/digitalrivercheckout-object/components/invoice-component)components require that you invoke a function that submits the data they collect and determines whether it's valid. Specifically, these components require that, inside of an [`async` function](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function), you call `done()` using the [`await`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/await) operator and then check the returned value to determine whether the checkout should advance to the next stage.

{% tabs %}
{% tab title="Address component" %}

<pre class="language-javascript"><code class="lang-javascript">...
<strong>const addressComponentStatus = await addressComponent.done();
</strong>if (!addressComponentStatus) {
  //Do not advance checkout to the next stage
  return;
} else {
  //Advance checkout to the next stage
}
...
</code></pre>

{% endtab %}

{% tab title="Tax identifier component" %}

```javascript
...
const taxIdentifierComponentStatus = await taxIdentifierComponent.done();
if (!taxIdentifierComponentStatus) {
  //Do not advance checkout to the next stage
  return;
} else {
  //Advance checkout to the next stage
}
...
```

{% endtab %}

{% tab title="Shipping component" %}

```javascript
...
const shippingComponentStatus = await shippingComponent.done();
if (!shippingComponentStatus) {
  //Do not advance checkout to the next stage
  return;
} else {
  //Advance checkout to the next stage
}
...
```

{% endtab %}

{% tab title="Invoice attribute component" %}

```javascript
...
const invoiceComponentStatus = await invoiceComponent.done();
if (!invoiceComponentStatus) {
  //Do not advance checkout to the next stage
  return;
} else {
  //Advance checkout to the next stage
}
...
```

{% endtab %}
{% endtabs %}

For details, refer to:

* [Submitting the address component](https://docs.digitalriver.com/digital-river-api/developer-resources/digitalrivercheckout.js-reference/digitalrivercheckout-object/components/address-component#submitting-the-address-component)
* [Submitting the shipping component](https://docs.digitalriver.com/digital-river-api/developer-resources/digitalrivercheckout.js-reference/digitalrivercheckout-object/components/shipping-component#submitting-the-shipping-component)
* [Submitting the tax identifier component](https://docs.digitalriver.com/digital-river-api/developer-resources/digitalrivercheckout.js-reference/digitalrivercheckout-object/components/tax-identifier-component#submitting-the-tax-identifier-component)
* [Submitting the invoice attribute component](https://docs.digitalriver.com/digital-river-api/developer-resources/digitalrivercheckout.js-reference/digitalrivercheckout-object/components/invoice-component#submitting-the-invoice-component)
