> For the complete documentation index, see [llms.txt](https://docs.borndigital.ai/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.borndigital.ai/digital-agent/advanced-functions/widgets.md).

# Widgets

Show forms, ratings, date pickers, file uploads and other interactive components in the chat, defined in JSON in the Answer node.

A widget is an interactive component shown in the chat below the agent's message: a form, a star rating, a date picker, a file upload and more. The customer fills it in, and the values arrive in the flow as variables.

Widgets are shown in the **DA Bubble** – the current chat bubble and the Studio test bubble. They are ignored in phone calls.

## Add a widget to an Answer node

1. Open the Answer node and go to the **Configuration** tab.
2. In the **Widget** section, stay on the **Configuration** tab and write the widget in **JSON code**.
3. Close the node, train the version and test it in the **Bubble**.

<figure><img src="https://4261467870-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F6iQTvxgRZRwPS1NgIGEb%2Fuploads%2Fgit-blob-985f6d55827006dc7c1fb287185f536479ff06be%2Fwidgets-answer-node-json.png?alt=media" alt="The Widget section of an Answer node with the Configuration tab and a Form widget in the JSON code editor"><figcaption><p>A widget in the JSON code editor of an Answer node</p></figcaption></figure>

{% hint style="warning" %}
Studio does not check the JSON. **Invalid JSON is skipped without an error** – the widget simply does not appear. Validate your JSON (for example in a JSON validator) before saving.
{% endhint %}

The second tab, **Configuration (Legacy)**, holds YAML widgets for the legacy Chatbot Bubble – see [Legacy YAML widgets](/digital-agent/advanced-functions/widgets/legacy-yaml-widgets.md). If both tabs are filled, the JSON widget is used.

## Widget Builder

The **Widget Builder** lets you write and check a widget before you put it into a flow. Open [customer-test.borndigital.ai/widget-builder](https://customer-test.borndigital.ai/widget-builder/) – no sign-in is needed. It has three parts:

* **Widget builder** – the widget canvas. Write or paste the widget JSON on the left (or **Upload JSON**), and the **Preview** on the right shows it exactly as the DA Bubble will. **Format JSON** tidies the code, **Copy** takes the finished JSON for the Answer node. To see the widget in a client's look, enter the **Bubble ID** and click **Load config**.
* [**Components**](https://customer-test.borndigital.ai/widget-builder/#components) – the reference of every widget component: what it does, which children it takes, and all its settings with their types, allowed values and limits, plus authoring notes. It is generated from the same component catalog the bubble uses, so it is always current.
* [**Icons**](https://customer-test.borndigital.ai/widget-builder/#icons) – the full HugeIcons catalog (more than 5,000 icons). Search for an icon and click it to copy its name, for example for `iconStart` on a `Button` or for the `Icon` component.

<figure><img src="https://4261467870-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F6iQTvxgRZRwPS1NgIGEb%2Fuploads%2FrQGGtu20q0QQzyCFjB0b%2Fwidget-builder-canvas.png?alt=media" alt="The Widget Builder canvas with the JSON configuration of a support-ticket form on the left and its live preview on the right, with Upload JSON, Format JSON, Bubble ID and Load config"><figcaption><p>The widget canvas: JSON on the left, live preview on the right</p></figcaption></figure>

<figure><img src="https://4261467870-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F6iQTvxgRZRwPS1NgIGEb%2Fuploads%2FqoG3UAbwcEdKCr8nrBsT%2Fwidget-builder-components.png?alt=media" alt="The Components reference in the Widget Builder with the component list and the Button component with its props, types and allowed values"><figcaption><p>The Components reference – every component with its settings</p></figcaption></figure>

{% hint style="info" %}
Use the Widget Builder to try a widget, then paste the JSON into the Answer node. Studio itself does not check widget JSON – the builder shows straight away whether the widget renders.
{% endhint %}

## Your first widget

A form that asks for an e-mail address:

```json
{
  "type": "Form",
  "gap": 12,
  "children": [
    { "type": "Input", "name": "contact_email", "inputType": "email", "placeholder": "Your e-mail", "required": true },
    { "type": "Button", "label": "Send", "submit": true }
  ]
}
```

When the customer clicks **Send**, the flow gets the variable `contact_email` with the entered address. The **Send** button stays disabled until the form is valid.

<figure><img src="https://4261467870-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F6iQTvxgRZRwPS1NgIGEb%2Fuploads%2Fgit-blob-d281ea8a69ca8c9c18511628c7d3f3b87b6a6b43%2Fwidgets-form.png?alt=media" alt="The form in the DA Bubble below the message Leave your e-mail and we will get back to you, with an e-mail address filled in and the Send button"><figcaption><p>The form in the bubble</p></figcaption></figure>

## How the JSON is built

* A widget is one **node** – an object with a `type` – or a list of nodes.
* Components are nested with `children`: a node, a list of nodes or a text.
* Settings are written **directly on the node**, for example `"label": "Send"` – not inside a `props` object.
* Every input field has a `name`. **The name becomes the variable** that holds the customer's answer. Fields without a `name` are not sent.
* Do not set `type` on a button to make it submit a form – `type` is the component name. Use `"submit": true`.

### Inserting values

* `{variable}` is replaced with the value of a flow variable when the node runs, for example `"placeholder": "{customer_email}"`.
* `%variable%` is filled in by the bubble when the widget appears – useful for prefilling a field: `"defaultValue": "%customer_email%"`.

Secret variables are never inserted.

## Components

For every component and all of its settings, see the [Components reference](https://customer-test.borndigital.ai/widget-builder/#components) in the Widget Builder. The tables below cover the ones used most.

**Layout and text**: `Box`, `Row`, `Col`, `Grid`, `Card`, `Carousel`, `Spacer`, `Divider`, `Text`, `Title`, `Caption`, `Label`, `Image`, `Icon`, `Badge`, `Tooltip`.

**Inputs and actions**:

| Component                                      | Use it for                             | Main settings                                                                                                                                    |
| ---------------------------------------------- | -------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------ |
| `Form`                                         | Groups fields and sends them together  | `children`                                                                                                                                       |
| `Button`                                       | Submitting a form or sending a message | `label`, `submit`, `onClickAction`, `variant` (`solid`, `soft`, `outline`, `ghost`)                                                              |
| `Input`                                        | Short text, e-mail, number, phone, URL | `name`, `inputType` (`text`, `email`, `number`, `tel`, `url`, `password`), `placeholder`, `required`, `pattern`, `defaultValue`, `errorMessages` |
| `Textarea`                                     | Longer text                            | `name`, `rows`, `autoResize`, `required`                                                                                                         |
| `Select`                                       | Choosing one option from a list        | `name`, `label`, `options` – a list of `{ "label": …, "value": … }`, `required`                                                                  |
| `RadioGroup`                                   | Choosing one of a few visible options  | `name`, `options`, `direction` (`col`, `row`), `required`                                                                                        |
| `Checkbox`                                     | Yes/no, consent, multiple choice       | `name`, `label`, `value`, `required`. An unticked box is not sent; several boxes with the same `name` send a list.                               |
| `DatePicker`                                   | A date                                 | `name`, `label`, `min`, `max` (`yyyy-MM-dd`). The value is sent as `yyyy-MM-dd`.                                                                 |
| `RatingStars`, `RatingNumbers`, `RatingThumbs` | Satisfaction, NPS, like/dislike        | `name`, `max` (stars 5, numbers 10), `min` (numbers), `submitOnChange` (default `true`)                                                          |
| `Autocomplete`                                 | Searching in a long list of options    | `name`, `options`, `multiple`, `allowCustomValue`                                                                                                |
| `DocumentUpload` with `UploadBox`              | Uploading files                        | `name`, `accept`, `maxFileSizeMb` (default 50), `multiple`, `valueFormat` (`files` or `urls`)                                                    |
| `Geolocation`                                  | The customer's location                | `name`, `automatic`. Sends `latitude` and `longitude`.                                                                                           |

### Buttons that send a message

A button can send a message on the customer's behalf instead of submitting a form:

```json
{ "type": "Button", "label": "My invoice", "onClickAction": { "type": "as_buttons", "payload": { "utterance": "invoice" } } }
```

<figure><img src="https://4261467870-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F6iQTvxgRZRwPS1NgIGEb%2Fuploads%2Fgit-blob-7d00d906812dfd5640472b8d19904de1361bc9d1%2Fwidgets-buttons.png?alt=media" alt="Two buttons, My invoice and Leave a contact, below the message Hi! What can I help you with? in the DA Bubble"><figcaption><p>Two such buttons in a Row</p></figcaption></figure>

Other actions: `as_links` opens a URL (`{ "url": "https://…", "variant": "new_tab" }`) and `as_restart` starts a new conversation.

### A star rating

```json
{ "type": "RatingStars", "name": "satisfaction", "max": 5 }
```

<figure><img src="https://4261467870-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F6iQTvxgRZRwPS1NgIGEb%2Fuploads%2Fgit-blob-4a3c88ce79d88804f169b96904a19b9d43ecb117%2Fwidgets-star-rating.png?alt=media" alt="Five empty stars below the message How satisfied are you with our service? in the DA Bubble"><figcaption><p>A star rating in the bubble</p></figcaption></figure>

A click sends the rating immediately as the message `rating_stars_<n>` (for example `rating_stars_5`). `RatingNumbers` sends `rating_numbers_<n>` and `RatingThumbs` sends `rating_thumbs_up` or `rating_thumbs_down`. Set `"submitOnChange": false` and put the rating in a `Form` to send it with other fields instead.

### A file upload

```json
{
  "type": "Form",
  "children": [
    {
      "type": "DocumentUpload", "name": "uploaded_documents", "multiple": true,
      "children": {
        "type": "UploadBox",
        "children": [
          { "type": "Text", "value": "Drop files here" },
          { "type": "Button", "label": "Choose files",
            "onClickAction": { "type": "open_document_upload_picker", "payload": { "name": "uploaded_documents" } } }
        ]
      }
    },
    { "type": "Button", "label": "Send", "submit": true }
  ]
}
```

<figure><img src="https://4261467870-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F6iQTvxgRZRwPS1NgIGEb%2Fuploads%2Fgit-blob-a3ee7cbd94521e1a6d2bc1bb725031174ad14db9%2Fwidgets-file-upload.png?alt=media" alt="An upload box with Drop files here and a Choose files button, and a Send button below it, in the DA Bubble"><figcaption><p>The file upload from the example above</p></figcaption></figure>

Accepted by default: PDF, JPG, PNG, HEIC, Word, Excel and PowerPoint files up to 50 MB each. Large photos are reduced before upload.

## Use the answer in the flow

**Form fields** become variables with the names of the fields, for example `contact_email`. Values arrive as text – a number as `"7"`, a ticked checkbox as `"true"`.

**Uploaded files**: with `"valueFormat": "files"` the variable holds a list of `{ id, documentName, documentType, url }`; with `"urls"` a list of URLs. The variable `binary_uploaded_document` also holds the URL of the file (or a list for several files).

**Branching**: in the Answer node, add a **Condition** intent on the variable, for example `contact_email != ""`. For buttons that send a message and for ratings, match the message with a **Keywords** intent (`invoice`, `rating_stars_5`) or a condition on `current_utterance`. Do not use AI intents for widget answers – they would see the technical text of the submission.

**If the customer types instead**: the customer can always ignore the widget and type a message. An open, valid form is still sent together with the message; otherwise the widget is skipped and disabled when the conversation moves on. Add `"persistOnSkip": true` to the top-level node to show the widget once more after an unrelated message.

{% hint style="info" %}
To make the customer answer only through the widget, turn off **Chat input field** in the Answer node's **Configuration** › **Chat features**.
{% endhint %}

## Pitfalls

* **No widget appears** – the JSON is invalid or a field is misspelled. Check it in a validator.
* **"Unknown widget type"** in the bubble – the `type` is not one of the components above.
* **A required file upload does not block sending** – disable the **Send** button until a file is uploaded, or check the variable in the flow.
* **A field is missing in the flow** – the field has no `name`, or its name collides with a secret variable or a variable that the API may not change.
