Custom widget
- Last UpdatedJul 03, 2026
- 7 minute read
Client Controls and OMI apps are supported only on desktop and do not work in the Web Client. Custom widgets provides a cross-platform solution, enabling you to develop once and use them across InTouch and OMI applications across web and desktop environments.
Prerequisites
Before you get started, ensure the following are installed:
-
Node.js (24.15.0 or later) and npm (11.12.1 or later): Required to install dependencies and build the widget package. Download them from nodejs.org.
-
Text editor: Used to edit widget files. Visual Studio Code is recommended.
This section explains how to create, build, and use a custom widget in InTouch and OMI applications. Follow the steps below:
-
Step 1: Create and modify a custom widget
-
Step 2: Update the project files
-
Step 3: Define widget properties and methods in the .wjson file
-
Step 4: Build the widget package
-
Step 5: Import and use the widget
Step 1: Create and modify a custom widget
A sample widget is available at C:\ProgramData\AVEVA\Widgets\SampleWidget to get started.
The Templates folder contains the base files used to create new widgets. Do not modify these template files during regular widget development.
-
Open the terminal in the WidgetCreator directory: C:\ProgramData\AVEVA\Widgets\WidgetCreator.
-
Run the following command to create a new widget
npm run create-widget MyWidgetName. Where, MyWidgetName is the name of the new widget.
-
Navigate to the newly created widget folder: cd MyWidgetName.
-
Open the new widget folder in Visual Studio Code to make changes.
Step 2: Update the project files
You can customize the following project files to build your widget:
-
index.html: Use to modify the HTML structure as required. This mandatory file is the main entry point and is loaded first when the widget is opened. Do not rename this file.
-
src/*.css: Use to customize the visual styles.
-
src/*.js: Use to implement the widget logic.
Note: The default CSS and JavaScript filenames are named after the sample widget. You can rename these files as required.
Step 3: Define widget properties and methods in the .wjson file
The .wjson file acts as a contract between the widget and InTouch and OMI applications. It defines the properties exposed by your widget to the platform.
Understand the .wjson structure
The .wjson file includes the following key fields:
-
version: Specifies the version of the widget.
-
width and height: Defines the default size of the widget when it is initially added.
-
events: Currently not implemented, but planned for future releases.
-
properties: Defines the widget properties exposed to the platform. Each property must be numbered sequentially starting from "0", then "1", "2", and so on.
Note: These fields are mandatory and must not be removed, as they are required for the widget to function correctly.
Configurable property fields
You can configure the following fields for each widget property:
-
Name: Specifies the widget property name displayed in InTouch and OMI. The name can be a maximum of 32 characters.
-
Type: Defines the data type of the property. Supported property types include boolean, double, elapsed time, float, integer, string, time, and history summary.
-
Value: Sets the default value assigned to the widget property.
-
Desc: Provides a description of the widget property. This field supports multiple languages to improve localization and usability.
The following example shows two properties. To add a new property, copy the full JSON entry and update the sequence number along with the name, type, and other relevant fields.
{
"version": 0,
"width": 500,
"height": 500,
"events": {},
"properties": {
"0": {
"name": "Counter",
"type": "integer",
"value": 0,
"desc": {
"1033": "Counter value",
"1036": "Valeur du compteur",
"1031": "Zählerwert",
"1041": "カウンター値",
"2052": "计数器值"
}
},
"1": {
"name": "Label",
"type": "string",
"value": "Count:",
"desc": {
"1033": "Display label",
"1036": "Étiquette d'affichage",
"1031": "Anzeigebeschriftung",
"1041": "表示ラベル",
"2052": "显示标签"
}
}
}
}
Use widget properties in JavaScript
Once you define your properties in the .wjson file, you can access them in JavaScript using cwidget.
Listen for property changes
To detect changes to a widget property, use the following pattern (replace 'Counter' with your actual property name):
cwidget.on('Counter', callbackFn);
callbackFn: A function executed whenever the property value changes. It can be used to update the UI or trigger additional logic.
Example from the sample widget:
In SampleWidget.js, when the 'Counter' property changes, the _onCounterCshanged() function is triggered to update the display:
cwidget.on('Counter', _onCounterChanged);
function _onCounterChanged() {
document.getElementById('counter').innerText = cwidget.Counter;
}
Set property values
To assign a new value to a widget property, use the following syntax:
cwidget.Counter = nextValue;
nextValue: Stores the value to be assigned to the property. It should match the data type of the property (for example, a number for an integer property or a string for a string property).
Example from the sample widget:
In SampleWidget.js, the increment button updates the Counter property. This automatically triggers the callback and updates all bound controls:
function _increment() {
const current = Number.parseInt(cwidget.Counter, 10) || 0;
cwidget.Counter = current + 1;
}
Bind callable methods in JavaScript (Optional)
To allow InTouch and OMI applications to call methods in your widget, you can expose the widget class methods by binding them to functions on the window object.
Below is an example (replace SampleWidget, Decrement, _decrement, and Counter with your own class and method names):
class SampleWidget {
constructor() {
window.Decrement = this._decrement.bind(this);
}
_decrement(args) {
var number = JSON.parse(args[0]);
const current = Number.parseInt(cwidget.Counter, 10) || 0;
const delta = Number.parseInt(number, 10) || 0;
cwidget.Counter = current - delta;
_onCounterChanged();
}
}
This creates a callable function named "Decrement", which can be used in industrial graphic action scripts after importing the widget.
Step 4: Build the widget package
After completing the development, follow the steps to build the widget and generate the deployable package:
-
Open a terminal in the widget folder (C:\ProgramData\AVEVA\Widgets\WidgetCreator\MyWidgetName).
-
Run the build command npm run build.
This generates a .cwp package in the dist folder.
Step 5: Import and use the widget
Once your widget is built, you can import it and use it in your application. Follow the steps to import the widget into InTouch application and bind its properties:
Import and embed the widget for InTouch WindowViewer
-
Open WindowMaker in your application.
-
Go to File > Import > Visualization > HTML5 widget.

-
Select the .cwp file generated in step 4.
-
Open the Graphic Editor and embed the widget from Industrial Graphics > Widgets.
Import and embed the widget for System Platform IDE
-
Open your Galaxy.
-
Go to the Home tab and select Import.

-
Select Web widgets.
-
Select the .cwp file generated in step 4.
After importing, your widget appears in the Graphic Editor toolbox, where you can drag and drop it onto your graphic.
Bind custom properties
Binding widget properties to custom properties enables two-way synchronization between your widget and other controls in your application.
Set up the binding
-
Create a custom property in your application. In this example, we use cp_value.

-
Bind the widget property to the custom property. In the widget property grid, link the Counter widget property to cp_value.
Two-way binding
Once the binding is set up, changes flow automatically in both directions:
-
From widget to application: When the widget updates its property (for example, cwidget.Counter = newValue), the cp_value custom property is updated, and all bound controls (such as a text box) reflect the new value.
-
From application to widget: When you enter a value in the text box, cp_value changes. This change triggers the callback function registered with cwidget.on(), allowing the widget to respond and keeps the UI synchronized.
Call widget methods from scripts
If you have defined callable methods in your widget (see Step 3: Bind callable methods in JavaScript), you can call a widget method from the Graphic Script editor.
In this example, create a button with an action script animation so that, when clicked, it triggers the Decrement method that was previously bound in JavaScript.
dim args [1] as object;
args[1]=5;
SampleWidget1.ExecuteFunctionAsync("Decrement",args);
For example, to invoke the Decrement function:

This script invokes the Decrement method on your widget instance, passing in a value of 5. When the button is clicked, the widget’s counter decreases by 5.
where,
-
SampleWidget1 is the name of the widget instance on the graphic.
-
ExecuteFunctionAsync is the method used to call widget functions asynchronously.
-
Decrement is the method name mapped to the JavaScript binding window. Decrement this._decrement.bind (this).
-
args is an object array that stores the arguments passed to the widget method. The array index should start at [1] (not [0]).
Replace SampleWidget1 with your actual widget name, and adjust the method name and arguments as needed.
Your custom widget is now fully integrated and ready to use.