Skip to content

How to work with checkout components

Checkout components provide functionality for ordering various products for discover.swiss frontend partners. These applications are compiled into native web-components and can be embedded into any website / web application. There are currently three web components:

Info

Before using these components, you need to go through a marketplace onboarding with our support.

Checkout Product Selector

This component monitors the click on the button for adding an item to the cart and activates the flow of choosing the collection of additional information that is needed to add the item to the cart (selection of size / color, etc. parameters when adding an item to the cart).

Usage notes and requirements

Before using the webComponent you need to load its script checkout-product-selector.js.

<script src="/path/or/url/to/checkout-product-selector.js"></script>

To be able to add product to the shopping cart each "add to basket" button should be wrapped like showed below. product-id should be replaced with the real product identifier.

Info

This component does not change the DOM.

<checkout-select-variant product-id="product-id">
        <button id="product-id" class="add-to-basket-btn" slot="productBtn">ADD TO BASKET</button>
</checkout-select-variant>

Checkout Product Variant Selector

This component is responsible for displaying product variants. It does not open in full screen and can be embedded anywhere on a web page.

Usage notes and requirements

Before using the webComponent you need to load its script checkout-product-variant-selector.js.

<script src="/path/or/url/to/checkout-product-variant-selector.js"></script>

To be able to show variants for the product product-id should be replaced with the real product identifier.

<checkout-product-variant-selector
    product-id="product-id"
    language="language"
    show-title="true|false"
    show-description="true|false"
    config="`
    {
      'assetsPrefix': 'path/to/static/files' or 'https://some.url.cdn.storage'
    }
  `">
</checkout-product-variant-selector>

Checkout Shopping Cart

The component displays the number of product Items in the shopping cart and activates checkout flow if you click on it.

Usage notes and requirements

Before using the webComponent you need to load its script checkout-shopping-cart.js.

<script src="/path/or/url/to/checkout-shopping-cart.js"></script>

checkout-shopping-cart tag should be placed at the place where you want to get clickable text/icon of the shopping cart. <span slot="checkoutShoppingCart">Checkout</span> should be placed between the checkout-shopping-cart tag.

Info

This component does not change the DOM.

...
  <ul class="menu-wrapper__items">
    <li class="menu-wrapper__item">
      <checkout-shopping-cart>
        <span slot="checkoutShoppingCart">Checkout</span>
      </checkout-shopping-cart>
    </li>
    <li class="menu-wrapper__item"><a href="#" target="_blank">projectPartner</a></li>
    ...
  </ul>
...

Checkout Core

This is the main web component. The previous two will not work without it. It handles all events coming from other components. Interacts with the backend. It also contains the flow of adding an item to the cart and checkout flow.

Usage notes and requirements

Before using the webComponent you need to load its script checkout-core.js.

<script src="/path/or/url/to/checkout-core.js"></script>

Since this component works with the backend and due to the fact that we can work with different versions of the backend environment, we need to configure it correctly. To do this, the component has a property config. Using this property, we need to pass a configuration object that has the following structure:

{
    subscriptionKey: string;
    profileUrl: string;
    marketplaceUrl: string;
    refreshTokenExpirationTimeInDays: number;
    forceToAuth: boolean;
    assetsPrefix: string;
    orderFulfillmentUrl: string;
    numberOfProfileMergingAttempts: number; // by default 3
    delayBetweenProfileMergingAttempts: number; // by default 500 milliseconds
    shortDelay: number; // delay in milliseconds between requests during shortDelayDuration
    longDelay: number; // delay in milliseconds between requests after shortDelayDuration period
    shortDelayDuration: number; // duration in milliseconds for frequent requests
    timeout: number; // stop observation after the timeout (milliseconds)
    orderInactivityDuration: number; // clear order, product, productVariant state after mentioned time of inactivity (milliseconds),
    showSavePaymentMethod: boolean; // if 'true', then you will see previously saved payment methods in the payment step, otherwise you will see only payment form
    directCheckout: boolean; // if 'true', then after the choosing product you will be redirected directly to the checkout steps (withoupt shopping cart)
    colorScheme: 'auto' | 'light-only' | 'dark-only'; // 'auto' - color scheme will be chosen based on user's OS preferences, 'light-only' - light color scheme will be used regardless of user's OS preferences, 'dark-only' - dark color scheme will be used regardless of user's OS preferences
    disableAuth: boolean; // optional, if 'true', then user will not see the suggestion to login in the checkout flow, default value is 'false'
    useCase: 'default' | 'tableReservation' // optional, if 'tableReservation', then it will change the UI of the checkout flow to the table reservation use case, default value is 'default' or even better to omit this parameter if you don't need this specific use case
    broadcastEventPrefix: string // optional, default value 'dsCheckout_' will be used under the hood, but you can change it if you want to avoid conflicts with other webcomponents on the same page

}

and result should be like this:

  ...
  <checkout-core config="`
    {
      'subscriptionKey': 'realSUbscriptionKeyForTheParticularEnvironment';
      'profileUrl': 'https://path/to/profile/api/url';
      'marketplaceUrl': 'https://path/to/marketplace/api/url';
      'refreshTokenExpirationTimeInDays': 10,
      'forceToAuth': false, // whether the webcomponent should require user authentication or can it work as a guest
      'assetsPrefix': 'path/to/static/files' or 'https://some.url.cdn.storage',
      'orderFulfillmentUrl': 'https://api.discover.swiss/dev/orderfulfillment', // used only for DEV ENV for handling payment step, you can omit this param for any other ENV
      'numberOfProfileMergingAttempts': 3
      'delayBetweenProfileMergingAttempts': 500
      'showSavePaymentMethod': true,
      'directCheckout': false,
      'colorScheme': 'auto'
    }
  `">
  <div slot="stripe-payment-element" id="stripe-payment-element-id">
    stripe-payment-element isn't mounted
  </div>
  </checkout-core>
</body>

Info

This component does not change the DOM.

To simplify component testing, we have implemented a default config, which contains the configuration for interacting with the test environment. Therefore, it is possible to omit the config parameter. In this case, there will be an interaction with the test environment.

Info

You can provide partial configuration. In this case, all fields that you omit will be taken from the default configuration.

Info

Note that you should avoid any caching of these endpoints (neither HTTP cache nor service workers):

'profileUrl': 'https://path/to/profile/api/url';
'marketplaceUrl': 'https://path/to/marketplace/api/url';
'orderFulfillmentUrl': 'https://api.discover.swiss/dev/orderfulfillment'; // used only for DEV ENV for handling payment step, you can
  ...
  <checkout-core>
    <div slot="stripe-payment-element" id="stripe-payment-element-id">
      stripe-payment-element isn't mounted
    </div>
  </checkout-core>
</body>

Styling

By default, the default discover.swiss color scheme is used (for light and dark modes) whose structure and color values can be seen below.

{
  ...
  style: {
        light: {
            '--primary-100': '#212121',
            '--primary-90': '#373737',
            '--primary-80': '#4d4d4d',
            '--primary-70': '#646464',
            '--primary-60': '#707070',
            '--primary-50': '#909090',
            '--primary-40': '#a6a6a6',
            '--primary-30': '#bcbcbc',
            '--primary-20': '#d3d3d3',
            '--primary-10': '#dddddd',
            '--primary-5': '#f0f0f0',
            '--primary-0': '#ffffff',
            '--accent-dark': '#b12527',
            '--accent-100': '#d02c2e',
            '--accent-70': '#db6a6f',
            '--accent-60': '#e38082',
            '--accent-30': '#e9a8ac',
            '--accent-secondary-dark': '#006610',
            '--accent-secondary-100':  '#008315',
            '--main-font': `'HK Grotesk', serif`,
            '--btn-background-color': 'var(--primary-0)',
            '--btn-border-color': 'var(--accent-100)',
            '--btn-text-color': 'var(--primary-100)',
            '--btn-background-color-hover': 'var(--primary-20)',
            '--btn-border-color-hover': 'var(--accent-100)',
            '--btn-text-color-hover': 'var(--primary-100)',
            '--btn-background-color-disabled': 'var(--primary-0)',
            '--btn-border-color-disabled': 'var(--primary-60)',
            '--btn-text-color-disabled': 'var(--primary-60)',
            '--btn-primary-background-color': 'var(--accent-100)',
            '--btn-primary-text-color': 'var(--primary-100)',
            '--btn-primary-background-color-hover': 'var(--accent-dark)',
            '--btn-primary-text-color-hover': 'var(--primary-100)',
            '--btn-primary-background-color-disabled': 'var(--primary-60)',
            '--btn-primary-text-color-disabled': 'var(--primary-100)',
            '--btn-confirmation-background-color': 'var(--primary-0)',
            '--btn-confirmation-border-color': 'var(--accent-secondary-100)',
            '--btn-confirmation-text-color': 'var(--accent-secondary-100)',
            '--btn-confirmation-background-color-hover': 'var(--primary-0)',
            '--btn-confirmation-border-color-hover': 'var(--accent-secondary-dark)',
            '--btn-confirmation-text-color-hover': 'var(--accent-secondary-dark)',
            '--btn-confirmation-background-color-disabled': 'var(--primary-0)',
            '--btn-confirmation-border-color-disabled': 'var(--primary-60)',
            '--btn-confirmation-text-color-disabled': 'var(--primary-60)',
            '--btn-primary-confirmation-background-color': 'var(--accent-secondary-100)',
            '--btn-primary-confirmation-text-color': 'var(--primary-100)',
            '--btn-primary-confirmation-background-color-hover': 'var(--accent-secondary-dark)',
            '--btn-primary-confirmation-text-color-hover': 'var(--primary-100)',
            '--btn-primary-confirmation-background-color-disabled': 'var(--primary-60)',
            '--btn-primary-confirmation-text-color-disabled': 'var(--primary-100)',
            '--footer-primary-background-color': 'var(--primary-100)',
            '--footer-default-background-color': 'var(--primary-0)',
            '--footer-primary-text-color': 'var(--primary-0)',
            '--footer-default-text-color': 'var(--primary-100)',
            '--spinner-color': 'var(--accent-100)',
        },
        dark: {
            '--primary-100': '#ffffff',
            '--primary-90': '#f0f0f0',
            '--primary-80': '#dddddd',
            '--primary-70': '#d3d3d3',
            '--primary-60': '#bcbcbc',
            '--primary-50': '#a6a6a6',
            '--primary-40': '#909090',
            '--primary-30': '#707070',
            '--primary-20': '#646464',
            '--primary-10': '#4d4d4d',
            '--primary-5': '#373737',
            '--primary-0': '#212121',
            '--accent-dark': '#b12527',
            '--accent-100': '#d02c2e',
            '--accent-70': '#db6a6f',
            '--accent-60': '#e38082',
            '--accent-30': '#e9a8ac',
            '--accent-secondary-dark': '#006610',
            '--accent-secondary-100':  '#008315',
            '--main-font': `'HK Grotesk', serif`,
            '--btn-background-color': 'var(--primary-0)',
            '--btn-border-color': 'var(--accent-100)',
            '--btn-text-color': 'var(--primary-100)',
            '--btn-background-color-hover': 'var(--primary-20)',
            '--btn-border-color-hover': 'var(--accent-100)',
            '--btn-text-color-hover': 'var(--primary-100)',
            '--btn-background-color-disabled': 'var(--primary-0)',
            '--btn-border-color-disabled': 'var(--primary-60)',
            '--btn-text-color-disabled': 'var(--primary-60)',
            '--btn-primary-background-color': 'var(--accent-100)',
            '--btn-primary-text-color': 'var(--primary-100)',
            '--btn-primary-background-color-hover': 'var(--accent-dark)',
            '--btn-primary-text-color-hover': 'var(--primary-100)',
            '--btn-primary-background-color-disabled': 'var(--primary-60)',
            '--btn-primary-text-color-disabled': 'var(--primary-100)',
            '--btn-confirmation-background-color': 'var(--primary-0)',
            '--btn-confirmation-border-color': 'var(--accent-secondary-100)',
            '--btn-confirmation-text-color': 'var(--accent-secondary-100)',
            '--btn-confirmation-background-color-hover': 'var(--primary-0)',
            '--btn-confirmation-border-color-hover': 'var(--accent-secondary-dark)',
            '--btn-confirmation-text-color-hover': 'var(--accent-secondary-dark)',
            '--btn-confirmation-background-color-disabled': 'var(--primary-0)',
            '--btn-confirmation-border-color-disabled': 'var(--primary-60)',
            '--btn-confirmation-text-color-disabled': 'var(--primary-60)',
            '--btn-primary-confirmation-background-color': 'var(--accent-secondary-100)',
            '--btn-primary-confirmation-text-color': 'var(--primary-100)',
            '--btn-primary-confirmation-background-color-hover': 'var(--accent-secondary-dark)',
            '--btn-primary-confirmation-text-color-hover': 'var(--primary-100)',
            '--btn-primary-confirmation-background-color-disabled': 'var(--primary-60)',
            '--btn-primary-confirmation-text-color-disabled': 'var(--primary-100)',
            '--footer-primary-background-color': 'var(--primary-100)',
            '--footer-default-background-color': 'var(--primary-0)',
            '--footer-primary-text-color': 'var(--primary-0)',
            '--footer-default-text-color': 'var(--primary-100)',
            '--spinner-color': 'var(--accent-100)',
        }
    }
    ...
}

Currently only hexadecimal color representation is supported. If you want to change any of the colors, then just add these values to your config. The existing values will be replaced with yours.

Example: I want to change few values (not only colors but font family as well) in this config for light and dark theme:

  <checkout-core config="`
    {
      'subscriptionKey': 'realSUbscriptionKeyForTheParticularEnvironment',
      'profileUrl': 'https://path/to/profile/api/url',
      'marketplaceUrl': 'https://path/to/marketplace/api/url',
      'refreshTokenExpirationTimeInDays': 10,
      'forceToAuth': false, // whether the webcomponent should require user authentication or can it work as a guest
      'assetsPrefix': 'path/to/static/files' or 'https://some.url.cdn.storage',
      'orderFulfillmentUrl': 'https://api.discover.swiss/dev/orderfulfillment', // used only for DEV ENV for handling payment step, you can omit this param for any other ENV
      'numberOfProfileMergingAttempts': 3,
      'delayBetweenProfileMergingAttempts': 500,
      style: {
        light: {
            '--accent-secondary-dark': '#007510',
            '--accent-secondary-100':  '#008525',
            '--main-font': `'Georgia', serif`,
            '--btn-text-color-disabled': '#757575',
        },
        dark: {
            '--accent-secondary-dark': '#007750',
            '--accent-secondary-100':  '#008950',
            '--main-font': `'Georgia', serif`,
            '--btn-text-color-disabled': '#959595',
    }
    }
  `">
  <div slot="stripe-payment-element" id="stripe-payment-element-id">
    stripe-payment-element isn't mounted
  </div>
  </checkout-core>
</body>

As you can see we can omit colors that we don't wan't to change.

Colors description

Below you can see a list of the variables which represent the colors of the application, actually this set of the variableS is the color scheme of the application. You can change any of these colors in the config.

  • primary-0 - the main color of the application. It is used for the background of the application, for the background of the non-primary buttons, for the background of the input fields

  • primary-5 - this color is used for the gray background (for light mode) of the main window of the application

  • primary-20 - this color is for some dividers (borders) in the application

  • primary-30 - this color is used as font color for the disabled date number in the calendar

  • primary-40 - this color is used as a background for the payment method and as a shadow color for the hovered payment method

  • primary-50 - this color is used as a border color for focused input fields

  • primary-60 - this color is used as a background for disabled primary buttons

  • primary-70 - this color is used as a background for buttons/controls of the inputs

  • primary-80 - this color is used for the font color of the labels for all inputs

  • primary-90 - this color is used as a font color for the payment method

  • primary-100 - the main color for the font of the application. It is used for the font color of the input fields, for the font color of the text in the application, for the font color of the headers, as a background for the action footer

  • accent-30 - this color is used as a border color for the focused inputs with error(s)

  • accent-60 - not used

  • accent-70 - this color is used as an icon color for the disabled icon buttons

  • accent-100 - this color is used for the background of the buttons in the application and as a border color for the non-primary buttons, for the links in the application, for the icons (which can be used as a buttons), for the spinner (loader) as a default color.

  • accent-dark - this color is used for the background of the hovered primary buttons

  • --accent-secondary-100 - this color is used for the background of the primary confirmation buttons in the application and as a border color for the non-primary confirmation buttons, for the 'insurance' checkbox

  • --accent-secondary-dark - this color is used for the background of the hovered primary confirmation buttons and as a border color for the hovered non-primary confirmation buttons

Except of the color scheme variable there are a set of the variables which represent the colors for the different parts of the application. They have quiet self-explanatory names. Below you can see a code example for the variables.

    '--btn-background-color': 'var(--primary-0)',
    '--btn-border-color': 'var(--accent-100)',
    '--btn-text-color': 'var(--primary-100)',
    '--btn-background-color-hover': 'var(--primary-20)',
    '--btn-border-color-hover': 'var(--accent-100)',
    '--btn-text-color-hover': 'var(--primary-100)',
    '--btn-background-color-disabled': 'var(--primary-0)',
    '--btn-border-color-disabled': 'var(--primary-60)',
    '--btn-text-color-disabled': 'var(--primary-60)',
    '--btn-primary-background-color': 'var(--accent-100)',
    '--btn-primary-text-color': 'var(--primary-100)',
    '--btn-primary-background-color-hover': 'var(--accent-dark)',
    '--btn-primary-text-color-hover': 'var(--primary-100)',
    '--btn-primary-background-color-disabled': 'var(--primary-60)',
    '--btn-primary-text-color-disabled': 'var(--primary-100)',
    '--btn-confirmation-background-color': 'var(--primary-0)',
    '--btn-confirmation-border-color': 'var(--accent-secondary-100)',
    '--btn-confirmation-text-color': 'var(--accent-secondary-100)',
    '--btn-confirmation-background-color-hover': 'var(--primary-0)',
    '--btn-confirmation-border-color-hover': 'var(--accent-secondary-dark)',
    '--btn-confirmation-text-color-hover': 'var(--accent-secondary-dark)',
    '--btn-confirmation-background-color-disabled': 'var(--primary-0)',
    '--btn-confirmation-border-color-disabled': 'var(--primary-60)',
    '--btn-confirmation-text-color-disabled': 'var(--primary-60)',
    '--btn-primary-confirmation-background-color': 'var(--accent-secondary-100)',
    '--btn-primary-confirmation-text-color': 'var(--primary-100)',
    '--btn-primary-confirmation-background-color-hover': 'var(--accent-secondary-dark)',
    '--btn-primary-confirmation-text-color-hover': 'var(--primary-100)',
    '--btn-primary-confirmation-background-color-disabled': 'var(--primary-60)',
    '--btn-primary-confirmation-text-color-disabled': 'var(--primary-100)',
    '--footer-primary-background-color': 'var(--primary-100)',
    '--footer-default-background-color': 'var(--primary-0)',
    '--footer-primary-text-color': 'var(--primary-0)',
    '--footer-default-text-color': 'var(--primary-100)',
    '--spinner-color': 'var(--accent-100)',

As you can notice we can use not only color value in some of the css valid format but also we can use the variables which were defined earlier. It is the good way to use the variables because it allows us to change the color scheme of the application in one place.

NOTE: This component does not change the DOM

Authentication

Guests or authorized users can interact with components.

If the user is not authorized, then at the first call to the api that requires user identification (for example, when viewing product variants), a guest token is created and recorded in the local storage.

dsGuestProfileToken: 'token'
dsRefreshGuestProfileToken: 'refresh_token'

This happens automatically and does not require any action from the user.

User authorization is also supported. In this case, the user must independently obtain an authorization token and pass it to the checkout-core component as the "autnToken" parameter:

<checkout-core auth-token="some_token" ...></checkout-core>

Web components can also fire authorization-related events that must be handled by the parent application. The list of events:

  • dsRefreshAuthTokenReq - this event fires when the web components detect that authToken has expired before adding the authToken to the request. In this case, you need to update the authToken and pass the updated version as a parameter to the checkout-core component;
  • dsForceAuthReq - this event fires when the user clicks on the login button inside the web components. In this case, the parent application should prompt the user to log in, and then pass the authorization token to the checkout-core;

Events

Web components can fire such events:

  • dsOpenProductDetails - this event fires when user clicks on the product name inside shopping cart;

Web components can respond to such events:

  • dsSendCloseShoppingCartEvent - web components listen for this event and the cart will be closed when it is received;

checkout-core events

These events are fired by the checkout-core component and can be handled by the parent application for some additional logic. The names of the events are prefixed with dsCheckout_ by default, but you can change this prefix by passing the broadcastEventPrefix parameter to the checkout-core component. The list of events:

  • {{ broadcastEventPrefix }}close (default is dsCheckout_close) - this event fires when the component is closed (for example, when the user clicks on the close button in the header of the component);

Language

The web components support English ('en'), German ('de'), French ('fr') and Italian ('it') languages, all the necessary translations are already contained within the web components. To select a language, you should pass "language" parameter to the checkout-core component:

    <checkout-core language="de, en, fr or it" ...></checkout-core>

If the language parameter is not passed, then the browser language is taken if it is English or German, otherwise the default language is German.

Required 3rd party fonts

The webComponents design currently employs the HT Groteks font, which must be added to comply with webComponents' limitations. After loading the checkout-core.js file, if you notice the following line in your head section, please rest assured that the script is automatically handling this addition.

<link href="http://fonts.cdnfonts.com/css/hk-groteks" rel="stylesheet">

Working example

Warning

To successfully complete the entire path from adding an item to the cart to placing an order with payment in TEST ENV, you need to open the page through the https connection (http protocol or open a file locally directly from the FS). Otherwise, the payment step will not work. These are the limitations of the payment system.

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <script src="./checkout-core.js"></script>
    <script src="https://cdn-test.discover.swiss/webcomponents/checkout/checkout-product-selector-0.js"></script>
    <script src="https://cdn-test.discover.swiss/webcomponents/checkout/checkout-product-variant-selector-0.js"></script>
    <script src="https://cdn-test.discover.swiss/webcomponents/checkout/checkout-shopping-cart-0.js"></script>
</head>
<body>
    <p>checkout-core</p>
    <checkout-core config='
      {
        "assetsPrefix": "https://cdn-test.discover.swiss/webcomponents/checkout/assets",
        "forceToAuth": false,
        "orderFulfillmentUrl": "https://api.discover.swiss/dev/orderfulfillment",
        "marketplaceUrl": "https://api.discover.swiss/dev/market",
        "profileUrl": "https://api.discover.swiss/dev/profile",
        "refreshTokenExpirationTimeInDays": 10,
        "stripeInteractionStrategy": "dev",
        "subscriptionKey": "d458b1d3733b43c09744517ab030a753"
      }
    '>
      <div slot="stripe-payment-element" id="stripe-payment-element-id">
        stripe-payment-element isn't mounted
      </div>
    </checkout-core>


    <p>Checkout-select-variant</p>
    <checkout-product-selector>
      <button id="nova_zurichcard" slot="productBtn">ADD TO BASKET</button>
    </checkout-product-selector>


    <br><br>
    <checkout-shopping-cart>
      <span slot="checkoutShoppingCart">Checkout shopping cart</span>
    </checkout-shopping-cart>

    <p>Checkout product variant selector</p>
    <checkout-product-variant-selector
      language="de"
      product-id="shopify_6544202104961"
      show-description="true"
      show-title="true"
      config='
        {
          "assetsPrefix": "https://cdn-test.discover.swiss/webcomponents/checkout/assets/"
        }
      '>
    </checkout-product-variant-selector>
</body>
</html>

Last update: February 1, 2024 17:37:15