Sample Custom Checkout Component

The Terms and Conditions sample component shows how to create a custom checkout component for a B2B or B2C store created with an LWR template. You can add a Terms and Conditions component to any section of your Checkout page, but we recommend placing it after the Payment component.

The Terms and Conditions component presents a checkbox to the customer. If the customer accepts the terms and conditions by selecting the box, they can continue the checkout process. Otherwise, the component blocks the checkout process. The checkbox text links to a page that describes your store’s terms and conditions, which you provide.

This example shows a Terms and Conditions component (1) placed in its own Terms and Conditions section after the Payment section.

Terms and Conditions Checkbox

You need four files to implement the Terms and Conditions component.

The first file is the LWC template: terms.html

1<template>
2    <div>
3        <input
4            type="checkbox"
5            id="termsandconditions"
6            name="terms"
7            checked={checked}
8            onchange={handleChange}
9        ></input>
10        <label class="slds-p-left_x-small" for="termsandconditions">
11            <lightning-formatted-rich-text
12                value={disclaimerLink}
13            ></lightning-formatted-rich-text>
14        </label>
15    </div>
16    <label if:true={showError} class="slds-text-color_error">
17        {error}
18    </label>
19</template>

The second file is the JavaScript component: terms.js:

1import { LightningElement, api } from "lwc";
2
3import { useCheckoutComponent } from "commerce/checkoutApi";
4
5const CheckoutStage = {
6  CHECK_VALIDITY_UPDATE: "CHECK_VALIDITY_UPDATE",
7  REPORT_VALIDITY_SAVE: "REPORT_VALIDITY_SAVE",
8  BEFORE_PAYMENT: "BEFORE_PAYMENT",
9  PAYMENT: "PAYMENT",
10  BEFORE_PLACE_ORDER: "BEFORE_PLACE_ORDER",
11  PLACE_ORDER: "PLACE_ORDER",
12};
13
14/**
15 * Terms and Conditions has a link to the terms and conditions for the
16 * checkout user to read and a checkbox to accept the terms. Place order
17 * should be blocked by this component when placed in the payment step
18 * before or after the payment component.
19 *
20 * One page layout: this component may be placed anywhere.
21 *
22 * Accordion layout: this component may be placed in its own section
23 * before the payment section or directly in the payment section
24 * before or after the payment component.
25 */
26export default class CheckoutTerms extends useCheckoutComponent(LightningElement) {
27  _checkedByDefault = false;
28  checked = false;
29  showError = false;
30
31  // The message to show to the shopper
32  @api
33  disclaimer = "I accept the [[Terms and Conditions]]";
34
35  // The link to the page containing the terms and conditions
36  @api
37  link = "/s/terms-and-conditions";
38
39  // The error message instructing the user to accept the terms
40  @api
41  error = "Please click the checkbox to accept the terms and conditions";
42
43  /**
44   * The terms may be checked by default from the builder property panel.
45   */
46  @api
47  get checkedByDefault() {
48    return this._checkedByDefault;
49  }
50
51  set checkedByDefault(value) {
52    this._checkedByDefault = value;
53    this.checked = value;
54  }
55
56  /**
57   * Embed a link directing in the disclaimer string.
58   */
59  get disclaimerLink() {
60    if (
61      this.disclaimer.indexOf("[[") > 0 &&
62      this.disclaimer.indexOf("[[") << this.disclaimer.indexOf("]]")
63    ) {
64      return this.disclaimer
65        .replace(
66          "[[",
67          `<a href="${this.link}"
68                            target="termsandconditions">`,
69        )
70        .replace("]]", "</a>");
71    }
72
73    return `<a href="${this.link}"
74        target="termsandconditions">${this.disclaimer}</a>`;
75  }
76
77  /**
78   * update form when our container asks us to
79   */
80  stageAction(checkoutStage /*CheckoutStage*/) {
81    switch (checkoutStage) {
82      case CheckoutStage.CHECK_VALIDITY_UPDATE:
83        return Promise.resolve(this.checkValidity());
84      case CheckoutStage.REPORT_VALIDITY_SAVE:
85        return Promise.resolve(this.reportValidity());
86      default:
87        return Promise.resolve(true);
88    }
89  }
90
91  /**
92   * Return true when terms checkoutbox is checked
93   */
94  checkValidity() {
95    return !this.checked;
96  }
97
98  /**
99   * Return true when terms checkbox is checked
100   */
101  reportValidity() {
102    this.showError = !this.checked;
103
104    if (this.showError) {
105      this.dispatchUpdateErrorAsync({
106        groupId: "TermsAndConditions",
107        type: "/commerce/errors/checkout-failure",
108        exception: "Terms and Conditions must be accepted first by clicking the checkbox",
109      });
110    }
111
112    return this.checked;
113  }
114
115  /**
116   * Check and uncheck the checkbox. Show error unless checked.
117   * @param {*} event
118   */
119  handleChange(event) {
120    this.checked = event.target.checked || false;
121    this.showError = !this.checked;
122  }
123}

The third file is the component’s metadata: terms.js-meta.xml

1<?xml version="1.0" encoding="UTF-8"?>
2<LightningComponentBundle xmlns="http://soap.sforce.com/2006/04/metadata">
3  <apiVersion>56.0</apiVersion>
4  <isExposed>true</isExposed>
5  <masterLabel>Terms and Conditions</masterLabel>
6  <targets>
7    <target>lightningCommunity__Page</target>
8    <target>lightningCommunity__Default</target>
9  </targets>
10  <targetConfigs>
11    <targetConfig targets="lightningCommunity__Default">
12      <property
13        label="Checked by Default"
14        name="checkedByDefault"
15        type="Boolean"
16        default="false"/>
17      <property
18        label="Disclaimer"
19        name="disclaimer"
20        type="String"
21        default="By clicking, you are confirming that your have read, understand and agree to the [[Terms and Conditions]]"/>
22      <property
23        label="Link URL"
24        name="link"
25        type="String"
26        default="/s/terms-and-conditions"/>
27      <property
28        label="Error Message"
29        name="error"
30        type="String"
31        default="Please click the checkbox to accept the terms and conditions"/>
32    </targetConfig>
33 </targetConfigs>
34</LightningComponentBundle>

And the fourth file is a checkout icon: terms.svg:

1<svg viewBox="0 0 52 52"
2    width="52"
3    height="52"
4    xmlns="http://www.w3.org/2000/svg"
5    xmlns:bx="https://boxy-svg.com">
6    <rect width="100%" height="100%" fill="#225f8c"/>
7    <path d="M 34.996 27.173
8             C 41.499 27.169 45.571 33.914 42.324 39.316
9             C 39.077 44.718 30.947 44.724 27.689 39.328
10             C 26.944 38.093 26.552 36.692 26.553 35.265
11             C 26.562 30.8 30.336 27.181 34.996 27.173
12             Z
13             M 21.34 34.522
14             C 23.637 34.522 25.072 36.904 23.923 38.81
15             C 22.776 40.716 19.906 40.716 18.757 38.81
16             C 18.496 38.375 18.357 37.883 18.357 37.381
17             C 18.357 35.802 19.693 34.522 21.34 34.522
18             Z
19             M 38.075 31.976 L 33.556 36.83 L 31.513 34.85
20             C 31.283 34.634 30.914 34.634 30.685 34.85
21             L 29.857 35.615
22             C 29.634 35.798 29.61 36.12 29.804 36.33
23             L 29.857 36.387
24             L 32.706 39.074
25             C 32.931 39.292 33.236 39.416 33.556 39.418
26             C 33.875 39.427 34.183 39.302 34.399 39.074
27             L 39.76 33.449
28             C 39.926 33.239 39.926 32.946 39.76 32.734
29             L 38.925 31.984 C 38.695 31.768 38.327 31.768 38.098 31.984
30             L 38.075 31.976
31             Z
32             M 12.272 9.054
33             C 13.046 9.072 13.72 9.561 13.95 10.269
34             L 14.412 11.812
35             L 40.73 11.812 C 41.345 11.797 41.859 12.26 41.879 12.849
36             C 41.886 12.964 41.871 13.077 41.834 13.185
37             L 38.717 23.657
38             C 38.663 23.89 38.525 24.098 38.329 24.243
39             C 37.245 23.944 36.122 23.791 34.996 23.785
40             C 33.602 23.794 32.221 24.036 30.916 24.5
41             L 20.595 24.5
42             C 19.689 24.492 18.947 25.19 18.939 26.058
43             C 18.938 26.241 18.97 26.423 19.036 26.595
44             L 19.036 26.651
45             C 19.247 27.34 19.906 27.811 20.654 27.81
46             L 25.949 27.81
47             C 25.071 28.789 24.373 29.903 23.883 31.105
48             L 18.089 31.105
49             C 17.307 31.11 16.62 30.612 16.411 29.889 L 11.004 12.356
50             L 9.386 12.356
51             C 8.412 12.341 7.635 11.574 7.648 10.641
52             L 7.648 10.597
53             C 7.762 9.706 8.56 9.04 9.497 9.054
54             L 12.272 9.054 Z"
55             style="paint-order: fill; fill: rgb(255, 255, 255);" bx:origin="0.507 0.496"/>
56</svg><svg viewBox="0 0 52 52" width="52" height="52" xmlns="http://www.w3.org/2000/svg" xmlns:bx="https://boxy-svg.com">
57    <rect width="100%" height="100%" fill="#225f8c"/>
58    <path d="M 34.996 27.173 C 41.499 27.169 45.571 33.914 42.324 39.316 C 39.077 44.718 30.947 44.724 27.689 39.328 C 26.944 38.093 26.552 36.692 26.553 35.265 C 26.562 30.8 30.336 27.181 34.996 27.173 Z M 21.34 34.522 C 23.637 34.522 25.072 36.904 23.923 38.81 C 22.776 40.716 19.906 40.716 18.757 38.81 C 18.496 38.375 18.357 37.883 18.357 37.381 C 18.357 35.802 19.693 34.522 21.34 34.522 Z M 38.075 31.976 L 33.556 36.83 L 31.513 34.85 C 31.283 34.634 30.914 34.634 30.685 34.85 L 29.857 35.615 C 29.634 35.798 29.61 36.12 29.804 36.33 L 29.857 36.387 L 32.706 39.074 C 32.931 39.292 33.236 39.416 33.556 39.418 C 33.875 39.427 34.183 39.302 34.399 39.074 L 39.76 33.449 C 39.926 33.239 39.926 32.946 39.76 32.734 L 38.925 31.984 C 38.695 31.768 38.327 31.768 38.098 31.984 L 38.075 31.976 Z M 12.272 9.054 C 13.046 9.072 13.72 9.561 13.95 10.269 L 14.412 11.812 L 40.73 11.812 C 41.345 11.797 41.859 12.26 41.879 12.849 C 41.886 12.964 41.871 13.077 41.834 13.185 L 38.717 23.657 C 38.663 23.89 38.525 24.098 38.329 24.243 C 37.245 23.944 36.122 23.791 34.996 23.785 C 33.602 23.794 32.221 24.036 30.916 24.5 L 20.595 24.5 C 19.689 24.492 18.947 25.19 18.939 26.058 C 18.938 26.241 18.97 26.423 19.036 26.595 L 19.036 26.651 C 19.247 27.34 19.906 27.811 20.654 27.81 L 25.949 27.81 C 25.071 28.789 24.373 29.903 23.883 31.105 L 18.089 31.105 C 17.307 31.11 16.62 30.612 16.411 29.889 L 11.004 12.356 L 9.386 12.356 C 8.412 12.341 7.635 11.574 7.648 10.641 L 7.648 10.597 C 7.762 9.706 8.56 9.04 9.497 9.054 L 12.272 9.054 Z" style="paint-order: fill; fill: rgb(255, 255, 255);" bx:origin="0.507 0.496"/>
59</svg>