> For the complete documentation index, see [llms.txt](https://dev.ubidots.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://dev.ubidots.com/plugins/private-plugins/widget.md).

# Widget

## Definition

A private widget plugin is a custom-developed widget that is available as if it were native to Ubidots. Like any other widget, it provides both execution logic and a graphical interface for user interaction.

Its visual rendering and logic execution happen when the dashboard loads. They continue only while the dashboard that contains it remains open.

For example, consider the following widget that uses the JavaScript Highcharts library for data plotting:

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

When a user opens the dashboard that contains this widget, the browser renders its visuals, and the logic that fetches and plots the data runs during load.

When the user leaves the dashboard, all tasks within the widget logic stop.

## Required files

As stated before, any private plugin, regardless of its type, and especially a private widget plugin, follows the file structure shown below:

```
├── src
│   ├── static                    
│   │   ├── widget.css      
│   │   ├── widget.html 
│   │   ├── widget.js             
│   ├── view.xml
│   ├── view_widget.xml
│   ├── control.py | control.js
│   ├── function.py | function.js
│   ├── user_code.py | user_code.js      
├── LICENSE
├── README.md
├── manifest.toml
```

## src and static directory

Unlike Cron and Webhook plugins, a Widget plugin includes an additional directory called `static`. This directory contains the widget's HTML, CSS, and JavaScript files.

{% hint style="warning" %}
Placing the CSS, HTML, and JS files in the root of *src*, instead of inside *static*, causes deployment errors.
{% endhint %}

## widget.css

Written in CSS, this file styles the widget's visual components.

## widget.html

Written in HTML, this file defines the layout of the widget's visual elements.

## widget.js

Written in JavaScript, this file handles the plugin's core logic and can also modify the CSS styles and HTML dynamically.

## Naming convention

You must keep the names of all files and directories listed in the "Required files" section, since the plugins engine specifically looks for these files and their extensions.

{% hint style="warning" %}
If you change the name of a file or directory, the plugin cannot be deployed.
{% endhint %}

## view\.xml

Although this file is only relevant to Cron and Webhook plugins, it must still contain valid placeholder data for the plugin to deploy.

## view\_widget.xml

The form that displays the widget's required parameters is created with `view_widget.xml`, **not** `view.xml`.

For example, suppose you are creating a widget that uses Highcharts to plot data. In that case, the widget requires the following information from the user:

* Variable label
* Title
* Subtitle
* X axis label
* Y axis label
* Series name

A form that contains those fields might look like this:

<figure><img src="/files/5pgVxrsrhwsLjs5uJsW5" alt="" width="563"><figcaption></figcaption></figure>

The form above can be built with `view_widget.xml` as follows:

```xml
<form>
    <inputcombo
        id="variable_label"
        type="text"
        label="Variable label"
        description="Device's variable label to use for the data"
        placeholder=""
        value=""
    />
    <inputcombo
        id="title"
        type="text"
        label="Chart's title"
        description="Chart's title"
        placeholder=""
        value=""
    />
    <inputcombo
        id="subtitle"
        type="text"
        label="Chart's subtitle"
        description="Chart's subtitle"
        placeholder=""
        value=""
    />
    <inputcombo
        id="x_axis_name"
        type="text"
        label="X-axis name "
        description="X-axis subtitle"
        placeholder=""
        value=""
    />
    <inputcombo
        id="y_axis_name"
        type="text"
        label="Y-axis name "
        description="Y-axis subtitle"
        placeholder=""
        value=""
    />
    <inputcombo
        id="series_name"
        type="text"
        label="Series name"
        description="Name for the series"
        placeholder="series 1"
        value=""
    />
</form>
```

All of these parameters in the form are accessible to the `widget.js` script using the Ubidots JavaScript class.

{% hint style="info" %}
For detailed information on how to access XML properties from within the `widget.js` script, refer to the corresponding section in the Plugins development page.
{% endhint %}

{% content-ref url="/pages/rS0xzSFJNeWovSJ42Sfh" %}
[Widget](/plugins/plugins-development/widget.md)
{% endcontent-ref %}

{% hint style="info" %}
For detailed information about the supported form elements, refer to the `view_widget.xml` section in the Plugins development page.
{% endhint %}

{% content-ref url="/pages/8k1p9YWRHCOVKqUXP9YJ" %}
[view\_widget.xml](/plugins/plugins-development/view_widget.xml.md)
{% endcontent-ref %}

## LICENSE and README.md files

Refer to the Private Plugins page for detailed information:

{% content-ref url="/pages/y6JQhF1KBcDzwb9Vtae2" %}
[Private plugins](/plugins/private-plugins.md)
{% endcontent-ref %}

## Manifest.toml

Aside from the previously mentioned manifest components common to all plugin types, the following are specific to widget plugins:

<table data-full-width="true"><thead><tr><th width="236">Section/subsection</th><th width="210.2">Key</th><th width="171">Value</th><th>Description</th><th>Example</th></tr></thead><tbody><tr><td>[settings.widget]</td><td>name</td><td>Any string</td><td>Name that the widget will display in the plugins drawer</td><td><pre><code>name = "My first widget plugin"
</code></pre></td></tr><tr><td>[settings.widget]</td><td>js_thirdparty_libraries*</td><td>A list of valid CDN URLs</td><td>List of libraries that the widget will import to use in its logic</td><td><pre><code>js_thirdparty_libraries = [
  "https://code.jquery.com/jquery-3.6.0.min.js",
  "https://code.jquery.com/moment-3.6.0.min.js"
]
</code></pre></td></tr><tr><td>[settings.widget]</td><td>css_thirdparty_libraries*</td><td>A list of valid CDN URLs</td><td>List of libraries that the widget will import to use in its styling</td><td><pre><code>css_thirdparty_libraries = [
  "https://code.jquery.com/jquery-3.6.0.min.css",
  "https://code.jquery.com/moment-3.6.0.min.css"
]
</code></pre></td></tr><tr><td>[settings.widget]</td><td>enable_lazy_load</td><td><code>true</code> or <code>false</code></td><td>Enables or disables lazy loading for the widget's visual components</td><td><pre><code>enable_lazy_load = true
</code></pre></td></tr></tbody></table>

With this in mind, a typical widget plugin `manifest.toml` file looks like this:

```
manifest_version = 2.0

[settings]
version = "1.1.1"
plugin_type = "widget"
license_name = "MIT license"

[settings.widget]
name = "Send data to device widget"  
js_thirdparty_libraries = [
  "https://code.jquery.com/jquery-3.6.0.min.js",
  "https://code.jquery.com/moment-3.6.0.min.js"
]
css_thirdparty_libraries = [
  "https://code.jquery.com/jquery-3.6.0.min.css",
  "https://code.jquery.com/moment-3.6.0.min.css"
]
enable_lazy_load = true
```

The keys marked with a \* in the table are optional. You do not need to import JS or CSS libraries. However, you should still define the key as an empty list.

For example, if no JS or CSS libraries need to be imported, the manifest looks like this:

```
manifest_version = 2.0

[settings]
version = "1.1.1"
plugin_type = "widget"
license_name = "MIT license"

[settings.widget]
name = "Send data to device widget"  
js_thirdparty_libraries = [ ] # No JS libraries are imported
css_thirdparty_libraries = [ ] # No CSS libraries are imported
enable_lazy_load = true
```


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## 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, and the optional `goal` query parameter:

```
GET https://dev.ubidots.com/plugins/private-plugins/widget.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

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.
