# Web Widgets Documentation

### Introduction

**Widgets** enhance the chat experience by allowing users to interact with rich, visual elements such as charts, forms, or interactive cards directly within the conversation. This is especially useful in cases where plain text isn't enough to convey complex information or guide a user through a task.

By integrating visual and interactive components, widgets improve usability and streamline workflows, making it easier for users to understand, explore, and act on information without leaving the chat.

One use case would be displaying a personalized calendar to check someone's availability and quickly and easily book an appointment or meeting.

There are two types of widgets:

* <mark style="color:purple;">**Default:**</mark> These are already configured to render specific information with easy implementation.
* <mark style="color:purple;">**Advanced:**</mark> These allow you to configure a widget from scratch for a specific need, giving you full control.

The key difference between predefined widgets and advanced widgets lies in how they're created. Predefined widgets come with built-in basic functionality, often requiring little to no additional setup. In contrast, advanced widgets offer complete flexibility, allowing you to define their functionality entirely based on how you configure them.

***

### How does the LLM interact with widgets?

Widgets are designed to be dynamically rendered based on the information provided by the LLM. The LLM is always aware of which widgets are available and when to invoke them.

The process is the following:

1. A widget is created with the necessary information to be rendered. This information may include data provided by the LLM if needed, specifically within the `config` and `parameters` sections.
2. The LLM adds the widget’s identifier (as defined in its file) to the context and uses the widget's description to determine when it should be invoked for rendering.
3. Once the widget is triggered, it will be displayed—either using additional data supplied by the LLM if required, or simply with its predefined configuration if no extra information is needed.
4. When required, the LLM uses available [Tools](/tools/create-a-tool.md) to gather and provide data to the widget. For example, it may call an API endpoint and use the response to dynamically populate the widget with relevant information.

> **Note:** This process is only possible if the web plugin is available.

<figure><img src="/files/VwFXOm3rGy275AVREhME" alt=""><figcaption></figcaption></figure>

***

### How to setup each default widget

In this section, we will explore what each default widget does, how to configure it, and how it interacts with the agent. Each default widget is designed to address a specific need in a general way, with easy configuration.

<details>

<summary>Calendly</summary>

This widget allows you to display a Calendly calendar to book meetings or appointments based on the Calendly profile link attached to the widget.

The fields that need to be configured are:

* <mark style="color:purple;">URL:</mark> This sets the link to the Calendly calendar that will be displayed. For example: <https://calendly.com/example-profile>
* <mark style="color:purple;">Description:</mark> Describe to the agent when this widget will be displayed in the chat.

Sequence process:

1. A widget will be created with description and configuration fields, which will include a URL.
2. The LLM will retrieve this information and call the widget when needed, based on the provided description.
3. The widget will be rendered via the URL in the configuration, but only if a web plugin is available. The widget does not function on WhatsApp

The LLM will retrieve the URL inserted through `companion.widgetConfig?.url`

<figure><img src="/files/0YQNpExrhJZbav5bW5vk" alt=""><figcaption></figcaption></figure>

</details>

<details>

<summary>Maps</summary>

This widget allows displaying a location on an interactive map (previously configured in the LLM instruction prompt) when the location is requested in the chat.

No fields is required, it is created directly.

Sequence process:

1. The widget will be created with a parameter that initially has no value, which will later interact with a URL.
2. The LLM will contain the URL information to be displayed and will call the widget as needed. This URL has to be the following structure: `https://www.google.com/maps?q=LAT,LONG&z=15&output=embed` and change the Latitude and Longitude.

*Prompt Example: Use this URL:* [*https://www.google.com/maps?q=37.3770029,-5.989754\&z=15\&output=embed*](https://www.google.com/maps?q=37.3770029,-5.989754\&z=15\&output=embed) *when asking about the location of Plaza de España in Seville.*

3. Once the widget is called, it will render the widget with the map by embedding the URL as the value of the configured parameter, but only if a web plugin is available. The widget does not function on WhatsApp.

The LLM will call the widget, embedding the value in the parameter through: `companion.widgetProps?.map_url`

<figure><img src="/files/UTEVvhf5aczW7eSJ6iTe" alt=""><figcaption></figcaption></figure>

</details>

<details>

<summary>Image Gallery</summary>

This widget displays an image carousel that has been previously configured in the LLM prompt, which will insert it into the widget. \
\
There are no required fields, the widget will be created directly.

Sequence process:

1. A widget is initialized with a parameter that is initially empty.
2. The LLM  generates a comma-separated list of image URLs based on a tool response when its called and passes this list to the widget as the parameter value.
3. Once the widget receives the parameter, it renders a carousel displaying the images.

The LLM will call the widget, embedding the value in the parameter through: `companion.widgetProps?.images`

<figure><img src="/files/456kwAFQnGpUvVkehOVY" alt=""><figcaption></figcaption></figure>

</details>

<details>

<summary>Typeform</summary>

This widget displays a Typeform form embedded via a provided URL, which has been previously configured in the LLM prompt and will be inserted into the widget.

\
The fields that need to be configured are:

* <mark style="color:purple;">URL:</mark> This sets the link to the Typeform form that will be displayed. For example: [https://form.typeform.com/to/e](https://form.typeform.com/to/dIJ3NiKf)xampleID
* <mark style="color:purple;">Description:</mark> Describe to the agent when this widget will be displayed in the chat.

Sequence process:

1. The widget will be created with description and configuration fields, which will include the Typeform URL.
2. The LLM will retrieve this information and call the widget when needed, based on the provided description and LLM instruction.
3. The widget will be rendered via the URL in the configuration, but only if a web plugin is available.

The LLM will retrieve the URL inserted through `companion.widgetConfig?.url`

<figure><img src="/files/13wLnpoXDWuNt6awDaas" alt=""><figcaption></figcaption></figure>

</details>

<details>

<summary>Product Catalog</summary>

This widget renders a product catalog based on information provided by the LLM. It is fully customizable, allowing you to choose which information to display and how to style it—by default, it adopts the color scheme of the configured chatbot.\
\
The fields that need to be configured are:

* <mark style="color:purple;">Display Properties:</mark> Select what key information you want to display and whether those properties need to be renamed.
* <mark style="color:purple;">In Page Navigation:</mark> Decide whether you want to browse through the products on the page or open them in a new browser tab.

<figure><img src="/files/teZcdSn5mO4E2fDfamRq" alt="" width="404"><figcaption></figcaption></figure>

* <mark style="color:purple;">Style Properties:</mark> Set the colors the widget should use to match the desired appearance. By default, it uses the colors from the configured web plugin.

<figure><img src="/files/atno7w5jrCWD7msxF6sk" alt="" width="407"><figcaption></figcaption></figure>

* <mark style="color:purple;">Description:</mark> Describe to the agent when this widget will be displayed in the chat.

Sequence process:

1. The widget will be created with the required fields in its configuration, and additionally, a "products" parameter will be automatically assigned. This parameter will not have an initial value but will contain the information of the products to be displayed in the catalog.
2. In the LLM prompt, the product widget will be called according to the required condition.**.**
3. When the widget is called, a tool will also be triggered beforehand, which will return the list of products to be rendered. This list will be assigned to the "products" parameter.
4. When the widget is rendered, it will use the information from the "products" parameter to display the product catalog.

<figure><img src="/files/rWvElWgkH90bmGFvGqqp" alt=""><figcaption></figcaption></figure>

<br>

</details>

***

### Widget Form Fields

* <mark style="color:purple;">**Widget File:**</mark> The required file that will render the widget with the code configured inside.
* <mark style="color:purple;">**Name:**</mark> The widget name that will be automatically introduced by the widget file attached
* <mark style="color:purple;">**Description:**</mark> The text that will detect the agent to invoke the widget when it will be requested
* <mark style="color:purple;">**Location Selector:**</mark> How the widget will be shown in the chat

  * <mark style="color:purple;">Dialog:</mark> The widget will be shown in a pop up window inside the conversation
  * <mark style="color:purple;">Page:</mark> The widget will be displayed in a chat window, within the full size of the web plugin
  * <mark style="color:purple;">Bottom Sheet:</mark> The widget will be shown at the bottom of conversation as a overlaid box
  * <mark style="color:purple;">Under Related Message:</mark> The widget will be shown inside of a chat message given by the agent response

  <figure><img src="/files/pDEGaaQDMlULTDyT2Uwh" alt=""><figcaption></figcaption></figure>
* <mark style="color:purple;">**Trigger Selector:**</mark> When the widget is going to be displayed

  * <mark style="color:purple;">Eager:</mark> The widget is going to be displayed instantly
  * <mark style="color:purple;">Input Field:</mark> The widget is going to be displayed when click in a input button
  * <mark style="color:purple;">Floating Action Button:</mark> The widget will be open clicking on a floating button at the bottom of the chat
  * <mark style="color:purple;">In Message Action:</mark> The widget is going to be displayed when click in a message button

  <figure><img src="/files/pbPSFiInbqytdw2KBUHL" alt=""><figcaption></figcaption></figure>
* <mark style="color:purple;">**Configuration:**</mark> Properties are created to provide additional information to the widget that modifies its behavior or display, allowing customization as desired using a key-value structure.

*(Example: A property is created to provide a URL that the widget requires to be rendered based on that URL.)*

* <mark style="color:purple;">**Parameters:**</mark> Objects with a predefined structure are created, which the widget will use to render the information based on their content. The widget will show this information when it is called. The object consists of:
  * <mark style="color:purple;">Type:</mark> Select the value type that will have the parameter (STRING , BOOLEAN, INTEGER, FLOAT)
  * <mark style="color:purple;">Name:</mark> The key name that will have the parameter
  * <mark style="color:purple;">Description:</mark> The text that will say when the parameter will be used
  * <mark style="color:purple;">Default Value:</mark> The initialized value that the parameter has when the is called
  * <mark style="color:purple;">Required:</mark> Determine if the default value is mandatory or not.

*(Example: When you want to render a product widget and display additional details not included in the widget file, the parameters will display those extra details.)*

***

### Create a Custom Widget

This section will explain how to create an advanced widget step by step, what its data structure is like, and what the relationship is between the LLM and the widget.

{% stepper %}
{% step %}
Create the Widget File

To start creating a widget, we first need to configure or create the file that will contain all the logic and code for the widget we want to render. This would be the basic structure of the code we’ll need:

```jsx
import { React, ReactDOM } from "<https://cdn.skypack.dev/es-react@16.13.1>";
import htm from "<https://cdn.jsdelivr.net/npm/htm@3.1.1/dist/htm.module.js>";
const html = htm.bind(React.createElement);

const WidgetComponent= ({ companion }) => {
  return html``;
};

function renderWidget(companion) {
  ReactDOM.render(
    html`<${WidgetComponent} companion=${companion} />`,
    window.loader.container()
  );
}

function unrenderWidget() {
  ReactDOM.render("", window.loader.container());
}

window.loader.register("widget_name", renderWidget, unrenderWidget);
```

Now let's go through each part of the code and explain what it is and what its functionality is.

* **Importing React and ReactDOM:**

  The code imports `React` and `ReactDOM` from a CDN using the `es-react` package, which offers lightweight React bindings ideal for embedding widgets.
* **Importing HTM:**

  The `htm` library is imported, allowing the use of HTML-like syntax in JavaScript without requiring JSX or a build process.
* **Binding HTM to React:**

  `htm` is bound to `React.createElement`, enabling the use of tagged template literals to write React components in a cleaner and more flexible way.

*This file is not tied to any specific framework—you can use **any JavaScript framework or library** to build your widget. React is just one example.*

```javascript
import { React, ReactDOM } from "<https://cdn.skypack.dev/es-react@16.13.1>";
import htm from "<https://cdn.jsdelivr.net/npm/htm@3.1.1/dist/htm.module.js>";
const html = htm.bind(React.createElement);
```

In this block of code, we define the component or function that will contain the information and logic for what we want to render. In this case, it will render a card with the name of a car, its image, and several details related to that car.

Access to the `config` and `parameters` info is available via `companion` prop, enabling extension of the code implementation as needed.

* To access `config`, use `companion.widgetConfig?.property_name`
* To access `parameters`, use `companion.widgetProps?.parameter_name`

```javascript
/*
//Base Component 

const WidgetComponent= ({ companion }) => {
  return html``;
};

*/

const CarWidget = ({ companion }) => {

// Use case with a config property to enter the name car in widgets page
const carName = companion.widgetConfig?.car_name
const carInfo = companion.widgetProps?.car_info

/* 
car_info = `{
  "engine": "2.3L EcoBoost® Engine with 315 HP",
  "additionalInfo": "Selectable Drive Modes",
  "features": "12.4” Digital Instrument Cluster and 13.2” Touchscreen" 
}`

*/

  return html`
    <div
      style=${{
        display: "flex",
        flexDirection: "column",
        justifyContent: "flex-start",
        alignItems: "center",
        width: "400px",
        boxShadow: "0px 4px 8px rgba(0, 0, 0, 0.1)",
        backgroundColor: "whitesmoke",
        borderRadius: "12px",
      }}
    >
      <p style=${{ fontSize: "2rem" }}>${carName || "Ford Mustang"}</p>

      <div style=${{ width: "100%", objectFit: "contain" }}>
        <img
          style=${{ width: "100%" }}
          src="<https://www.vdm.ford.com/content/dam/na/ford/en_us/images/mustang/2025/jellybeans/Ford_Mustang_2025_100A_PYZ_88D_89W_13A_COU_64F_99H_44U_EBST_DEFAULT_EXT_4.png>"
        />
      </div>

      <div
        style=${{
          display: "flex",
          flexDirection: "column",
          alignItems: "center",
          gap: "6px",
          maxWidth: "90%",
          textAlign: "center",
        }}
      >
        <p style=${{ margin: 0 }}>${carInfo.engine}</p>
        <p style=${{ margin: 0 }}>${carInfo.additionalInfo}</p>
        <p style=${{ margin: 0 }}>${carInfo.features}</p>
      </div>
    </div>
  `
}
```

This block of code has `renderWidget` function that is responsible for rendering the widget into the DOM.

* It receives a `companion` object as a parameter, which contains the data that will be passed to the widget.
* Inside the function, `ReactDOM.render()` is used to render the `WidgetComponent` and inject it into the DOM element returned by `window.loader.container()`.
* The `companion` object is passed as a prop to the `WidgetComponent`, allowing it to use that data when rendering its content.

```javascript
function renderWidget(companion) {
  ReactDOM.render(
    html`<${CarWidget} companion=${companion} />`,
    window.loader.container()
  )
}
```

The `unrenderWidget` function is responsible for **removing the rendered widget** from the DOM.

* It uses `ReactDOM.render()` to render an empty string (`""`), which essentially removes the existing content inside the container.
* The second argument, `window.loader.container()`, specifies the DOM element where the widget was originally rendered. This ensures that the content is removed from the same location.

```javascript
function unrenderWidget() {
  ReactDOM.render("", window.loader.container())
}
```

This method **`window.loader.register`** is used to register the widget with a loader, allowing it to be managed dynamically (e.g., shown or removed based on some conditions).

* **`"show_car"`**: This is the name or identifier for the widget. It's essentially a label that the loader will use to recognize and manage this widget.
* **`renderWidget`**: This is the function that will be called when the widget needs to be rendered (i.e., displayed on the page). It contains the logic to inject the widget into the DOM.
* **`unrenderWidget`**: This is the function that will be called when the widget needs to be removed from the page. It contains the logic to clear the widget from the DOM.

```jsx
window.loader.register("show_car", renderWidget, unrenderWidget)
```

{% endstep %}

{% step %}
Complete the required fields

When a valid JavaScript file for the widget has been attached, an input field will appear displaying the identifier name of the widget that has been configured in the file:

<figure><img src="/files/8biA48WRdx12bY4E7Lfk" alt=""><figcaption></figcaption></figure>

Now, you need to write a description of the widget, which will explain when it will be invoked by the agent.

Prompt examples for description:

* *When the user is interested in Ford Mustang car call this widget*
* *When user shows interest in booking a meet call this widget*
* *When user ask for a location call this widget*

Also, select the modes for how the widget will be displayed (Location Selector) and how the widget will be opened (Trigger Selector), with the option to hide the trigger if desired.

<figure><img src="/files/hZtoO45VxyFUe77Jp8es" alt=""><figcaption></figcaption></figure>
{% endstep %}

{% step %}
(Optional) - Add extra information

And as the last step, if desired, extra information can be added in Config and Parameters, which will enhance the widget's potential according to the needs.

<figure><img src="/files/1cBRBmWeAa9udsCIYNfL" alt=""><figcaption></figcaption></figure>

Once the widget has been successfully created, you can interact with the agent, and depending on how it's configured, it will call the widget whenever it's needed in the conversation:

<figure><img src="/files/QdbE0xTHTmM7DtNeKkS2" alt=""><figcaption></figcaption></figure>

When a widget is created has the following structure:

```json
{
  "id": "abc-abc-abc-abc-abc",
  "created": "2025-04-03T07:15:31.286405Z",
  "modified": "2025-04-03T07:15:31.286405Z",
  "parent": "message",
  "trigger": "ima",
  "source": "https://file-in-cloud.com",
  "description": "When this widget is going to be used",
  "name": "widget_name",
  "config": {
    "car_name": "Ford Mustang",
  },
  "parameters": {
   "car_info": {
      "id": "abc-abc-abc-abc-abc",
      "key": "car_info",
      "type": "string",
      "default": "",
      "required": false,
      "placement": "data",
      "properties": {},
      "description": "The info of the car"
    }
  },
  "active": null,
  "project": "abc-abc-abc-abc-abc",
  "user": "abc-abc-abc-abc-abc"
}
```

```tsx
interface Widget {
  id: string;
  created: string;
  modified: string;
  parent: "message" | "dialog" | "sheet" | "page";
  trigger: "eager" | "ima" | "input" | "fab";
  source: File; // File attached as FormData
  description: string;
  name: string;
  config: null | Record<string, unknown>; // Transform to JSON
  parameters: null | Record<string, { // Transform to JSON
    id: string;
    key: string;
    type: "string" | "boolean" | "integer" | "float";
    required: null | string | number | boolean;
    placement: "data";
    properties: {};
    description: string;
    default: string;
  }>;
  active: null;
  project: string;
  user: string;
}
```

* <mark style="color:purple;">**id:**</mark> Unique widget identifier, automatically assigned by the Caleida API.
* <mark style="color:purple;">**created:**</mark> The timestamp indicating when the widget was initially created. Set automatically by the Caleida API.
* <mark style="color:purple;">**modified:**</mark> The timestamp of the most recent update to the widget, also set automatically by the Caleida API.
* <mark style="color:purple;">**parent**</mark> *<mark style="color:purple;">(Location Selector)</mark>*<mark style="color:purple;">:</mark> Specifies how and where the widget will appear when invoked.
* <mark style="color:purple;">**trigger**</mark> *<mark style="color:purple;">(Trigger Selector)</mark>*<mark style="color:purple;">:</mark> Defines the mechanism or event that opens the widget.
* <mark style="color:purple;">**source**</mark> *<mark style="color:purple;">(Widget File)</mark>*<mark style="color:purple;">:</mark> The uploaded file containing the widget's rendering code.
* <mark style="color:purple;">**description:**</mark> A text prompt that helps the agent determine when to invoke the widget.
* <mark style="color:purple;">**name:**</mark> The name of the widget, automatically extracted from the attached widget file.
* <mark style="color:purple;">**config:**</mark> A list of properties that provide additional metadata or settings for the widget.
* <mark style="color:purple;">**parameters:**</mark> A list of objects used to supply additional contextual information when the widget is triggered.
* <mark style="color:purple;">**active:**</mark> Indicates whether the widget is currently active or not.
* <mark style="color:purple;">**project:**</mark> Identifier of the project where the widget was created; set automatically by the Caleida API.
* <mark style="color:purple;">**user:**</mark> Identifier of the user who created the widget; also automatically set by the Caleida API.
  {% endstep %}
  {% endstepper %}


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.caleida.io/widgets/web-widgets-documentation.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
