Elements integration guide

In this section, we provide a brief overview of a BILL Elements integration. We first showcase an example and then we break down each component in the example.

Example integration code

In this sample code, we see the key components for adding BILL Elements to your web page.

We first set up the BILL bootloader module, and then add authentication configuration. We finally render and display a BILL Element on your web page with the specified CSS style and theme.

In this example, we set up the Add funding Element (fundingAdd).

<!DOCTYPE html>
<html>
<head>
  <!-- Establish BILL CDN connection with the BILL CDN base URL -->
  <!-- Improves load time -->
  <link 
    rel="dns-prefetch preconnect"
    href="https://widgets.stage.bdccdn.net/"
    crossorigin
  />
  <!-- Preload the bootloader script with the bootloader module -->
  <!-- Optimizes overall performance -->
  <link
    rel="preload"
    as="script"
    href="https://widgets.stage.bdccdn.net/bootloader/index.js"
  />

  <!-- Custom CSS for Elements styling -->
  <link rel="stylesheet" href="{path_to_element.css}">

<!-- Other <head> tags -->
</head>

<body>
  <!-- Your page markup -->
  <div id="your-div" class="your-element-style"></div>

  <!-- Before the closing </body> tag; Import BILL bootloader -->
  <script type="module">
    import { init } from 'https://widgets.stage.bdccdn.net/bootloader/index.js';

    // Elements configuration information
    const billBootConfig = {
      key: '{set_your_developer_key}',
      getSessionId: () => localStorage.getItem('sessionId'),
      getUserContext: () => {
        const userId = localStorage.getItem('userId');
        const orgId = localStorage.getItem('orgId');
 	      return { userId, orgId };
      },
      onAuthFailed: () => Promise.resolve(),
      onEvent: (event) => console.log(event)
    };

    // Initialize & mount the Element on the web page
    // Set name as the Element name. For example, `fundingAdd`.
    const bootloader = init(billBootConfig);
    bootloader.register({
      id: 'element1',
      name: 'fundingAdd'
    });
    await bootloader.render('element1', '#your-div');
    
    // Element cleanup
    // Destroy only when the user has left the experience 
    // or when the component is unmounted
  	window.addEventListener('beforeunload', () => {
      bootloader.destroy('element1');
	  });
  </script>
</body>
</html>

Key components

There are five key components in a BILL Elements integration.

1. Preconnect and preload setup

In the <head> tag of your web page, add <link> tags with information for improving the Element load time. This step is important for avoiding any latency issues with loading Elements.

👍

preconnect & preloadsetup depends on your templating engine

This is one example for the Elements setup. The format in which you add your preconnect and preload setup may depend on your web templating engine.

The web templating engine or system is a tool that helps separate the content of a web page from its presentation (layout and style). Examples include Handlebars (JavaScript templating engine) and Liquid (Ruby-based templating engine).

<!DOCTYPE html>
<html>
<head>
  <!-- Establish BILL CDN connection with the BILL CDN base URL -->
  <!-- Improves load time -->
  <link 
    rel="dns-prefetch preconnect"
    href="https://widgets.stage.bdccdn.net/"
    crossorigin
  />
  <!-- Preload the bootloader script with the bootloader module -->
  <!-- Optimizes overall performance -->
  <link
    rel="preload"
    as="script"
    href="https://widgets.stage.bdccdn.net/bootloader/index.js"
  />

Establish BILL CDN connection

Use the <link> tag to establish a connection with the BILL CDN. With the preconnect link tag, we provide a set of instructions to the web browser.

  1. The web page intends to establish a connection with the BILL CDN, and
  2. The web browser must begin the connection process early in the web page loading process.

Preload bootloader script

Use the <link> tag to preload the BILL bootloader module that is required for rendering and displaying BILL Elements. With the "preload" link tag, we instruct the web browser to start loading the required resources (scripts, styles, and fonts) early in the web page loading process.

2. Element styling and themes

In the <head> tag of your web page, add <link> tags with information to define the default CSS for your Element and improve its load time. This step is important for avoiding any latency issues with loading the Elements. You can then use classes from the stylesheet in your markup.

  <!-- Custom CSS for Elements styling -->
  <link rel="stylesheet" href="{path_to_element.css}">

<!-- Other <head> tags -->
</head>

<body>
  <!-- Your page markup -->
  <div id="your-div" class="your-element-style"></div>

In this sample CSS file, we set custom properties for your Element.

.your-element-style {
  --bill-color-action: hsl(1.36deg 77.19% 55.29%);
  --bill-color-text-primary-inverse: hsl(0deg 0% 100%);
  --bill-color-text-secondary: hsl(60deg 1.09% 36.08%);
  --bill-color-text-primary: hsl(0deg 0% 0%);
  --bill-radius-button: 1rem;
}

Custom CSS properties

BILL provides a set of custom CSS properties that you can set for your widget styling and themes.

PropertyDescriptionDefault value
--bill-color-actionPrimary color for interactive elements, such as buttons or linkshsl(245 54% 50%)
—-bill-color-text-primary-inverseText color for elements where --bill-color-action is applied. For example, button text color.hsl(0deg 0% 100%)
—-bill-color-text-secondaryColor for secondary text elements, such as input help texthsl(60 1% 36%)
—-bill-color-text-primaryColor for primary text elements, such as headers or paragraphshsl(0 0% 0%)
--bill-color-errorColor for error elements, such as error banners or texthsl(3 70% 41%)
--bill-color-warningColor for warning elements, such as warning banners or texthsl(34 94% 69%)
--bill-color-successColor for success elements, such as success banners or texthsl(151 100% 20%)
--bill-color-infoColor for information elements, such as information banners or texthsl(0 0% 0%)
--bill-radius-buttonButton border radius1rem
--bill-radius-bannerBorder radius for banners1rem
--bill-radius-tagBorder radius for tags1rem
--bill-color-linkColor for linkshsl(245 54% 50%)
--bill-color-illustration-primaryPrimary color for SVG illustrationshsl(245 54% 50%)
--bill-color-illustration-accentAccent color for SVG illustrationshsl(0 0% 0%)
--bill-font-weight-regularFont weight for paragraphs and interactive elements300
--bill-font-weight-emphasisEmphasized font weight for headers, tags, lists, and menus500

3. Import the Elements bootloader

At the end of the <body> tag of your web page, add a <script> tag to import the init() function from the BILL bootloader module. This is required for the next set of steps for interacting with Elements.

<!-- Before the closing </body> tag; Import BILL bootloader -->
 <script type="module">
    import { init } from 'https://widgets.stage.bdccdn.net/bootloader/index.js';

4. Element authentication configuration

BILL provides a set of bootloader configuration properties that are required for authenticating your developer account with your session ID.

Generate your organization-level sessionId with POST /v3/login. See API login in the API reference for more information.

In the <script> tag, add the Element configuration information, which includes your BILL authentication details (developer key and sessionId). Generate sessionId with POST /v3/login.

🚧

Use HttpOnly cookies or save the session in memory in production

In the Production environment, use HttpOnly cookies or save the session information in memory. Do not use localStorage in the Production environment.

If you must use localStorage in the Production environment, ensure that your Content Security Policy (CSP) is strict.

    // Element configuration information
    const billBootConfig = {
      key: '{set_your_developer_key}',
      getSessionId: () => localStorage.getItem('sessionId'),
      getUserContext: () => {
        const userId = localStorage.getItem('userId');
        const orgId = localStorage.getItem('orgId');
        return { userId: userId, orgId: orgId };
      }
      onAuthFailed: () => Promise.resolve(),
      onEvent: (event) => console.log(event)
    }

Bootloader authentication properties

BILL provides a set of bootloader authentication properties.

Property

Description

key

Developer key generated with your BILL developer account

getSessionId

Use the getSessionId callback to return a partner sessionId that is required by your Element to make authenticated API calls to the BILL v3 API. See API partner login in the API reference to learn about signing in and generating a partner-level sessionId.

Use this function for one of two scenarios.

  • For returning the sessionId as a string value, or
  • For returning a resolved promise as a string value

getUserContext

Use the getUserContext callback to return the current userId and orgId in the {userId: string, orgId: string} format. When a BILL organization is created, an orgId is generated. When a user is created for the organization, a userId is generated.

Your Element requires userId and orgId for ensuring that the currently signed-in user has the required permissions to perform operations on the current BILL organization. See Organizations for BILL partners and Users for BILL partners for more information.

onAuthFailed

Use the onAuthFailed callback to handle API sign in failure or API session expiration. Use this function for returning a resolved promise with a valid sessionId when the sign in operation and authentication is successful.

onEvent

Use the optional onEvent callback to handle bootloader-specific events for website fingerprint profiling. BILL implements policies for creating a trusted device profile. As an enhanced security measure, all website visits are tested against the fingerprinting profile.

  • fingerprintSuccess: Website fingerprinting is successful
  • fingerprintError: An array of strings that states the error with website fingerprinting Note that this process does not affect website load time.

You can also use window.addEventListener for handling bootloader-specific events for website fingerprint profiling at this stage.

window.addEventListener('bill-bootloader', (event) => {
   console.log(event);
});

// Output format:
// { type: 'fingerprintSuccess', payload: {} }
// OR
// { type: 'fingerprintError', payload: { errors: ['Invalid session'] } }

5. Initialize the Element experience

In the <body> tag of your web page, complete the Element initialization script in your <script> tag.

    // Initialize & mount the Element on the web page
    // Set name as the Element name. For example, `fundingAdd`.
    const bootloader = init(billBootConfig);
    bootloader.register({
      id: 'element1',
      name: 'fundingAdd'
    });
    await bootloader.render('element1', '#your-div');

BILL provides a set of functions that help with initializing the Element experience on your web page.

Function

Description

init()

Use the init() function to get a reference to the BILL bootloader instance. This function is required to register and render your Elements.

register()

Use the register() function to register the Element with the BILL bootloader instance. You can specify details about the Element that you want to include on your web page. See the next set of sections for details about the inputs and outputs objects.

  • id: Unique identifier. This can be any string value.
  • url: Element URL
  • inputs: Optional key-value pair of input for the Element. This can be information for pre-populating fields in the Element, and also for directing users to the correct flows in the experience.
  • outputs: Optional key-value pair of output from the Element. This output can be events generated from the Element, and can be handled with window.addEventListener or the onEvent callback.

render()

Use the render() function to return a promise that resolves when an Element is successfully loaded (initialized and mounted) on your web page.

Add input to an Element

When initializing the Element experience, you can use the register() function to add input to the Element. This can be information for pre-populating fields in the Element, and also for directing users to the correct flows in the experience.

For example, if a vendorId input is available in the vendor setup, the user is directed to the update vendor flow.

    // Initialize & mount the Element on the web page
    const bootloader = init(billBootConfig);
    bootloader.register({
      id: 'element1',
      name: '{element_name}',
      inputs: {
        vendorId: "{vendor_id}"
      }
    });
    await bootloader.render('element1', '#your-div');

Listen to output generated by an Element

When initializing the Element experience, you can use the register() function to listen to a set of lifecycle events generated by the Element. You can use window.addEventListener or an onEvent callback for listening to and handling these Element events.

Event

Payload format

Description

statusChange

{ status: event }

Possible event values: 'mounting', 'mounted', 'unmounted', or 'error'

Element event status change

error

{ error: string }

Javascript error

mounted

{ node: HTMLElement }

Element is mounted on your web page

unmounted

{ node: HTMLElement }

Element is unmounted from your web page

window.addEventListener

You can use window.addEventListener for handling Element events at this stage.

    // Initialize & mount the Element on the web page
    const bootloader = init(billBootConfig);
    bootloader.register({
      id: 'element1',
      name: 'fundingAdd'
    });
    await bootloader.render('element1', '#your-div');
    window.addEventListener('element1', (event) => {
       const data = event.detail;
       console.log(data);
    });

// Output format:
// { name: string; payload: {} }
onEvent

You can use the onEvent callback for handling Element events at this stage.

    // Initialize & mount the Element on the web page
    const bootloader = init(billBootConfig);
    bootloader.register({
      id: 'element1',
      name: 'fundingAdd',
      outputs: {
         onEvent: (event) => console.log(event)
      }
    });
    await bootloader.render('element1', '#your-div');

// Output format:
// { name: string; payload: {} }

Selected Events

When the user clicks a link in any of the Elements, a Selected event is emitted. This event can be handled in two ways, and you have several options for each.

BILL handles the navigation

BILL does not handle the navigation

When this occurs

The user clicks a link that points to a screen inside the current BILL Element.

The user clicks a link that points to a screen outside (a separate Element or a page in your custom application) the current BILL Element.

Example

The user clicks Edit in the Vendors Element, and a screen opens within that same Element to edit the vendor details.

The user clicks add a new vendor in the Schedule Payment Element. The user is navigated to the Vendors Element to add a new vendor.

BILL default action

Fires an event upon clicking and automatically navigates the user to the destination.

Only fires an event upon clicking and does not navigate. The link is non-functional by default.

Your options

  • Allow default routing: Ignore the event

  • Implement custom routing: Listen to the event and navigate the user to a page in your application.

  • Implement custom routing: Listen to the event to navigate the user

  • Ignore the event: Ignore the event. The link will be non-functional

  • Hide the link (future enhancement): Pass an input to hide the link.
    NOTE: This functionality is currently under development.

showLinks

These inputs control the display of links and calls to action (CTA) in the Element. If you do not want to hook up handling for these links or CTAs, you can choose to hide them within the Element. Set showAll to true to display all links, or use showIndividual to selectively control each link.

{
  showAll: boolean;
  showIndividual: {
    showScheduleAPaymentLink?: boolean;
    showPaymentDetailsLink?: boolean;
    showAddVendorLink?: boolean;
    showRestoreVendorLink?: boolean;
    showSwitchToEPayLink?: boolean;
    showEditVendorLink?: boolean;
    showSendConnectionReminderLink?: boolean;
    showCancelConnectionLink?: boolean;
    showRequestToConnectLink?: boolean;
    showVendorDetailsLink?: boolean;
    showCancelPaymentLink?: boolean;
    showVoidPaymentLink?: boolean;
    showVendorDetailsLink?: boolean;
    showAddFundingLink?: boolean;
    showPaymentDetailsVendorLink?: boolean;
  };

6. Element cleanup

With the render() function for Element initialization, you can render the Element with the query selector or node element reference method. All BILL Elements are set up to automatically clean up when the query selector or node that was passed to the bootloader is removed.

When you want to manually clean up a Element, use the destroy() function to manually perform the cleanup action.

NOTE: In the <body> tag of your web page, complete the Element cleanup. This is an optional step. Destroy only when the user has left the experience or when the component is unmounted.

    // Element cleanup
    // Destroy only when the user has left the experience
    // or when the component is unmounted
  	window.addEventListener('beforeunload', () => {
      bootloader.destroy('element1');
	  });
  </script>
</body>
</html>