Skip to main content

Widget lifecycle management

Kapa's JavaScript API supports render() and unmount() functions which give you manual control over the widget state. They are especially useful in Single-Page Applications (SPAs) or other environments where you need to change the widget's visibility or behavior across different pages.

Overview

The render() function asynchronously mounts and initializes the global Kapa object. It optionally accepts an onRender callback that executes after the widget has been fully rendered. Use this callback to perform subsequent actions (such as opening the widget) to ensure they occur only after initialization is complete.

The unmount() function removes the widget's DOM elements and clears its references. Call this when you want to remove the widget from the page (for example, when navigating away from a page that should display the widget).

Use case

In SPAs, where the widget exists outside your component tree, you can control its lifecycle manually, rendering it only on pages that require it and unmounting it otherwise.

The lifecycle functions provide an API for manually transitioning between the possible widget states:

  • Unmounted: The widget is completely removed from the DOM.
  • Mounted and closed: The widget is rendered but not open.
  • Mounted and opened: The widget is rendered and actively open.

Preinitialize Kapa

When you manage the widget's lifecycle manually using the JavaScript API, you may want to consider preinitializing Kapa to avoid calling functions before the script has loaded. Preinitializing Kapa ensures that calls to render() and unmount() are queued properly even if the widget script hasn’t finished loading, preventing errors when these functions are called early.

Usage examples

The following examples show different examples of how to manage the widget's lifecycle using the render() and unmount() functions.

info

These examples all reference a loadScriptIfNotExists() setup function, which loads the widget and disables the default render-on-load behavior. See Appendix: setup function.

Vanilla JavaScript

Mounted and opened
// Ensure the widget script is loaded
loadScriptIfNotExists();

// Render the widget with an onRender callback to open it once rendered
window.Kapa("render", {
onRender: () => window.Kapa("open"),
});

// If the widget is already rendered on this page, call open directly
window.Kapa("open");
Mounted and closed
loadScriptIfNotExists();
// calling render when the script is already rendered is harmless,
// it will just log a warning: “widget already rendered”
window.Kapa("render");
Unmounted
// Unmount the widget in case it was rendered on another page
window.Kapa("unmount");

React

In React, managing the widget’s lifecycle is straightforward using the useEffect hook, which lets you automatically clean up when the component unmounts, removing the need for handling the "unmounted" state explicitly.

Mounted and opened
useEffect(() => {
loadScriptIfNotExists();
window.Kapa("render", {
onRender: () => {
window.Kapa("open");
},
});

return () => window.Kapa("unmount");
}, []);
Mounted and closed
useEffect(() => {
loadScriptIfNotExists();
window.Kapa("render");

return () => window.Kapa("unmount");
}, []);

Appendix: setup function

function loadScriptIfNotExists() {
const scriptSrc = "https://widget.kapa.ai/kapa-widget.bundle.js";

// Check if the script already exists in the document
if (document.querySelector(`script[src="${scriptSrc}"]`)) {
console.log("Kapa widget script is already loaded.");
return;
}

const script = document.createElement("script");

// Set the async property correctly
script.async = true;
script.src = scriptSrc;

// Define other script attributes
const attributes = {
"data-website-id": "6d04c434-4090-4ebf-aeb3-8e90645a504d",
"data-project-name": "kapa.ai",
"data-project-color": "#5B4CFE",
"data-project-logo": "kapa.ai/assets/logo.png",
"data-render-on-load": "false",
};

// Set attributes on the script element
Object.entries(attributes).forEach(([key, value]) => {
script.setAttribute(key, value);
});

// Append to the document head
document.head.appendChild(script);
}