React components can be connected to the Appsmith platform using the Widget Development APIs and registered to be available for use by Appsmith developers.
- In the above video, we can view a quick walk through on the basics of the Widget Development API.
- In the following, we dive into the details of the features available to widget developers.
Appsmith developers: Users who use the Appsmith platform to build apps for their consumers
Widget developers: Developers who create widgets that are then available to the Appsmith developers to use.
Entities: Building blocks of an Appsmith application. These are Widgets, Queries, APIs, appsmith.store
and JS Objects.
Widgets: Entities in the Appsmith Ecosystem. These are UI building blocks, similar to components in any other design system, used in Appsmith to build UI.
- Appsmith developers can configure widget properties and event handlers while building an Appsmith application.
- Widget developers can decide which properties and events are exposed to Appsmith developers via the Appsmith platform.
These are the values that define the state of a Widget. If an Appsmith developer expects to update the state of Widget1 using data from other entities, they will need to bind
the other entity as a property of Widget1.
For example, the Text Widget has a property text
. This defines the displayed text in a Text Widget. If an Appsmith developer expects the value from an Input widget to be displayed in Text Widget, the Input widget’s text property would have to be bound
with the Text widgets’ text
property.
{{ Input1.text }}
Example
Here, Input1
is the name of the Input widget. text
is the property of the Input widget, which contains the value we’d like to display in the Text widget. {{ }}
allows the platform to evaluate
the content within the brackets. This means that we can write JS code within {{ }}
if we’d like to manipulate the entity properties. For example,
{{ Input1.text.toLowerCase() }}
We can read more about bindings
here.
Many widgets are interactive. These widget interactions can be used to trigger workflows in web applications. This is what separates static web pages from web applications. For example, a Button widget has an interaction of click. Hence, the onClick
action trigger is exposed, whose handler can be configured by the Appsmith developer.
As an example, let’s say we’d like to show a message at the click of a button widget. We can configure it like so: {{ showAlert("My message", "info") }}
Here, showAlert
is an action provided by the Appsmith platform. “My Message”, is a string that will be displayed in the alert. “info” is a showAlert
specific parameter, which describes the type of message.
Example
More on the platform provided action triggers can be found here
We can also, bind
entity properties here. For example,
{{ showAlert(Text1.text, "info") }}
Here, Text1.text
is the text
property of a Text widget named Text1
.
We can also use JS here. {{ showAlert(Text1.text.toLowerCase(), "info") }}
Now that we’ve seen how an Appsmith developer configures a widget, let's take a look at how a widget is developed
Widget code resides in the src/widgets
folder of the Appsmith codebase. Each widget has its own folder. As shown in the screenshot above, widget folders contain the following files and folders -
index.ts
- This file contains the configuration for a widget.
constants.tsx
- This file contains the constants which will be used in the widget and its components.
icon.svg
- This is the SVG file for the icon representing the widget.
widget/index.tsx
- This contains the widget code, which utilises the Widget development API and lets the Appsmith platform know how to render a widget.
component/index.tsx
- This contains the core component which is rendered on the main canvas.
Canvas: A canvas is a special type of widget, in the Appsmith platform, within which widgets can be placed by the Appsmith developer. For example, a Container Widget contains a Canvas Widget, this allows us to place other widgets within a container widget.
We can generate the folder structure using this command from the CLI -
cd app/client && yarn generate:widget
For a widget to be listed by the Appsmith application, it has to be registered with the Appsmith platform. This can be done by calling registerWidget
with the details of the widget in the registerWidgets
function.
registerWidget
(required, void): Appsmith utility function used to register a widget.
Arguments:
-
Widget
: A class which extendsBaseWidget
-
config
: Widget configuration (CONFIG
described below)
This exports the widget configuration as an object usually named CONFIG
. The default export has to be the widget itself. An example is shown here
type
(required):Widget.getWidgetType()
, whereWidget
is the default import from thewidget/index.tsx
name
(required): The display name of this widget. This can contain spaces.iconSVG
(required):IconSVG
, whereIconSVG
is the import from the./icon.svg
needsMeta
(optional):true
, if this widget stores temporary values. For example, a user input value or state.isDeprecated
(optional): This property indicates whether the widget is deprecated. If set totrue
, it means the widget is no longer recommended for use, and developers should consider using the specified replacement widget.isCanvas
(optional):true
, if this widget contains a Canvas within itself, to allow for widgets to be placed within.properties
(required):
derived: Widget.getDerivedPropertiesMap(),
default: Widget.getDefaultPropertiesMap(),
meta: Widget.getMetaPropertiesMap(),
config: Widget.getPropertyPaneConfig(),
defaults
(required): The default properties of a widget. The platform provided common configurations:
This can have the rest of the default properties for the widget. Any property not defined here will default to undefined
. Widget developers are expected to handle these properties accordingly. - rows
(required): Number of rows occupied by default by this widget when placed on a canvas. - columns
(required): Number of columns occupied by default by this widget when placed on a canvas. - widgetName
(required): The auto-generate widget name prefix, for this type of widget. This cannot have spaces or special characters. - version
(required): The version number of this type of widget. - blueprint
(optional): The blueprint of the widget. - enhancements
(optional): Enhancements that can be applied over widgets.
- All configurations can affect how the widget behaves. Misconfiguration can cause errors.
- Some constants and types are provided by the Appsmith platform. These can be imported from
src/WidgetsProvider/constants
. See more blueprint
andenhancements
are powerful features that can be used to create complex widgets. We have more information here.
The widget code must be all available in the widget
folder. index.tsx
should export the class which extends BaseWidget
.
getPropertyPaneConfig
(required,[PropertyPaneConfig[]](#property-pane-configuration)
): returns the property pane configurationgetPropertyPaneContentConfig
(required,[PropertyPaneConfig[]](#property-pane-content-configuration)
): returns the property pane content configurationgetPropertyPaneStyleConfig
(required,[PropertyPaneConfig[]](#property-pane-style-configuration)
): returns the property pane style configurationgetDerivedPropertiesMap
(optional, DerivedPropertiesMap): returns the map of properties which can be derived from other properties. We can see more details heregetDefaultPropertiesMap
(optional, object): returns the list of properties which by default takes the value of a default propertygetMetaPropertiesMap
(optional, object): returns the properties which will be considered and stored as meta properties.getWidgetType
(required, string): returns a unique type for the widget.
-
executeAction
(void): Executes an action. Typically, used to call the configured action triggers. Arguments:triggerPayload
ExecuteTriggerPayload Note:undefined
ornull
actions throws an error.
-
disableDrag
(void): Prevents the widget from being dragged in the canvas. For example, the Table Widget disables widget drag when re-ordering columns using header drag. This allows for widgets to implement features without conflicting with the platform features.disable
Argument which disables drag whentrue
, enables whenfalse
.
-
updateWidgetProperty
(void): Updates a single widget propertypropertyPath
: Path of the property to updatepropertyValue
: Value to be set
-
deleteWidgetProperty
(void): Deletes a particular widget property -
batchUpdateProperty
(void): Updates multiple properties. Arguments:updates
: Argument type BatchUpdatePropertyPayloadshouldReplay
(boolean): Iffalse
, it will not be considered as a state to which an Appsmith developer canundo
(cmd+z
orctrl+z
). Defaulttrue
.
-
resetChildMetaProperty
(void): Resets all meta properties of children of this widget. Arguments:widgetId
: CurrentwidgetId
-
updateWidgetMetaProperty
(void): Different fromupdateWidgetProperty
, these updates are not persisted across refreshes. Meta properties are transient properties, typically, user input. Arguments:propertyPath
(any, required): Property path to updatepropertyValue
(any, required): Value of the property.actionExecution
(DebouncedExecuteActionPayload, optional): Action if any to execute along with property update,
-
getPageView
(ReactNode, required ): Enhanced version of React.render. This should return the React component which needs to render on the canvas.
Derived properties are the ones that are computed from other properties of the widget. For example, the isValid
property of a Rich Text Editor Widget can be computed using the isRequired
and text
properties. This widget’s text should be invalid if the widget is configured to require a value, and the text is empty. A simple JS conditional can help us assign a value to the isValid
property.
{{ this.isRequired ? this.text && this.text.length : true }}
In this example, we have derived a new property from two (isRequired, text) existing properties.
Note: this
keyword is the widget’s context. In this case, the Rich Text Editor Widget.
Using the described mechanism, getDerivedPropertiesMap
should return an object where the keys are the derived property names, and the values are strings with JS bindings to compute the derived property value.
Default properties are maps that define the default (configured in property panes) values of other properties. For example, in a Rich Text Editor Widget, the text
property contains the user input content. However, it can also be configured to have a default starting value from the property pane. The property which is configured in the property pane is called defaultText
. By using the getDefaultPropertiesMap
API, widget developers can define how text
gets its default value.
static getDefaultPropertiesMap(): Record<string, string> {
return {
text: "defaultText",
};
}
Note: When a new value of defaultText
is provided, it overrides the text
value.
Meta properties are properties whose values are transient and not persisted in the application. For example, the user-provided content (text property) in the Rich Text Editor Widget is not persisted. However, this content is stored in memory and can be used in bindings.
We can configure these using the getMetaPropertiesMap
API.
static getMetaPropertiesMap(): Record<string, any> {
return {
text: undefined,
};
}
Note: The values provided must be undefined
if this property is also used in other APIs like getDerivedPropertiesMap
Property pane configuration defines the order of property controls, their validations, grouping, types, etc.
The type is `Array``.
Example:
Property pane content configuration defines the settings related to the content and functionality of the widget, including the order of property controls, their validations, grouping, types, etc.
The type is `Array``.
Example:
Property pane style configuration defines the settings related to the appearance and styling of the widget, including the order of property controls, their validations, grouping, types, etc.
The type is `Array``.
Example:
This object defines sections in the property pane.
-
sectionName
(required, string): Display name of the section -
children
(required,PropertyPaneConfig[]
): Usually, a list of property controls to show in this section. See PropertyPaneControlConfig -
hidden
(optional, boolean): A function that defines if this section is hidden. Arguments: -props
: The current widget properties -
propertyPath
: The path relative to the widget to this section. If not in a panel, this is usually the widget itself.
This object defines the property control’s configurations
-
label
(required, string): Name of the property displayed to the Appsmith developer -propertyName
(required, string): Property key with which to associate the value. -
helpText
(optional, string): A description to help the Appsmith developer understand the property better. Shows up in a tooltip when hovering over the label. -
isJSconvertible
(optional, boolean): Is the Appsmith developer allowed to use the JS button to allow bindings for this property. -
controlType
(required, ControlType): Type of the control. -
panelConfig
: (optional, PanelConfig: Does this property open a panel? If so, panel configurations must be defined here. -
isBindProperty
(required, boolean): Can this property’s value be defined using bindings by an Appsmith developer -
isTriggerProperty
(required, boolean):true
if this is an event handler that can trigger actions -
updateHook
(optional,Array<{propertyPath: string; propertyValue: any}> | undefined
): This function is used to define any other properties which need to be updated when this property is updated. This function executes before the new property value is stored and evaluated. All property updates returned from this function will be applied simultaneously along with the original property update.Arguments
-
props
(any): The widget’s properties. -
propertyName
(string): The path to the widget property -
propertyValue
(any): The new value of the property the Appsmith developer is trying to apply. - The return value should be an array of objects orundefined
. The keys of the object are described below.
Return
-
Type:
Array<{propertyPath: string; propertyValue: any}> | undefined
-
propertyPath
: Path to the property which needs to be updated -
propertyValue
: Value of the property which needs to be updated.
-
-
hidden
(optional, boolean): A function that returnstrue
if this property should be hidden.Arguments:
-
props
: The current widget properties -
propertyPath
: The path relative to the widget to this property.
-
-
additionalAutoComplete
(optional, nested object): A function that returns additional entries for the autocomplete in this property.Arguments:
props
: Current widget properties
Return
-
Type:
Record<string, Record<string, unknown>>
-
This returns an object which has keywords as keys and an object as value, whose keys will be used for auto-complete.
-
dependencies
(required forupdateHook
andhidden
, string[]): This lists the property paths which will be needed for computations in thehidden
andupdateHook
functions. This is an optimisation that allows for a small subset of widget properties to be used for computations. -
validation
(required, ValidationConfig): The configuration which defines how to validate this property. -
customJSControl
(optional, ControlType): If we have a special control which we would like to show in place of the standardINPUT
control.
This configuration helps in defining the details of properties shown in a panel.
editableTitle
(required, boolean): It defines if the title of the panel is editable.titlePropertyName
(required, string): It defines the root path to the properties within the panel.children
(required, PropertyPaneConfig[]): It configures the sections and controls show within the panel.[updateHook](#propertypanecontrolconfig)
Example
Properties can be required to be validated when an Appsmith developer is allowed to use bindings. It helps maintain the integrity of widgets. Widget developers can expect validated properties when validations are provided.
-
type
(required, ValidationTypes): The type of validation to be performed. -
params
(required for some validation types, ValidationConfigParams): Parameters provided to help with the validation.min
(optional, number): Used to specify a minimum value forValidationTypes.NUMBER
max
(optional, number): Used to specify a maximum value forValidationTypes.NUMBER
natural
(optional, number): Used to validate a number as a natural number. Used withValidationTypes.NUMBER
default
(optional, unknown): Used to provide a default value to an invalid orundefined
property value.unique
(optional, boolean | string[]): Used to specify the paths in the property which need to be unique. See example.required
(optional, boolean): Specifies if the value of this property, is mandatory for the widget to function correctly.regex
(optional, RegExp): Regex to match text value inValidationTypes.TEXT
allowedKeys
(optional, Array<Record<string, unknown>>): Array of configurations for the allowed keys inValidationTypes.OBJECT
.name
(required, string): Name of the keytype
(required, ValidationTypes): The type of validation for the value of this keyparams
(optional, ValidationConfigParams): Parameters provided to help with the validation
allowedValues
(optional, unknown[]): An array containing the set of allowed values forValidationTypes.ARRAY
children
(optional, ValidationConfig): Validation configuration for entries inValidationTypes.OBJECT_ARRAY
fn
(optional,(value: unknown, props: any, _?: any, moment?: any) => ValidationResponse
): The function used to validation inValidationTypes.FUNCTION
- Arguments
- Return value
- ValidationResponse: A specific format that the Appsmith platform uses to understand validation results.
isValid
(required, boolean): Specifies if the property value is validparsed
(required, unknown): The value after validation. This could be the default or the original value or a formatted version of the original value.messages
(optional, string[]): An array of messages used to describe how the validation has failed. This helps Appsmith developers identify and fix issues in property configurations
- ValidationResponse: A specific format that the Appsmith platform uses to understand validation results.
expected
(required forValidationTypes.FUNCTION
, CodeEditorExpected): A structure that describes the expected type, example and autocomplete data type.type
(required, string): The type of the property to be shown to the Appsmith developerexample
(required, ExpectedValueExample): An example of the value expected for the property.autocompleteDataType
(required, AutocompleteDataType): Describes how the auto-complete feature for this property should work.
strict
(optional, boolean): If set totrue
, values inValidationTypes.TEXT
, will not be cast to a string before validating.ignoreCase
(optional, boolean): If set totrue
, keys will be matched while ignoring case inallowedKeys
parameter of theValidationTypes.OBJECT
.ValidationTypes.FUNCTION
is meant to be used sparingly, and as an escape hatch when the otherValidationTypes
do not fit the requirements of validation.- All validations return a
ValidationResponse
A widget blueprint is a configuration that can allow widget developers to describe the structure of widget's children and any modifications to their properties. This structure will be applied with this type of widget is placed on the canvas by an Appsmith developer.
For example, a Form Widget by default contains a canvas within which there is a text widget and button widgets. This is configured in the widget configuration here
A widget blueprint configuration can have two parts. view
and operations
Widget Blueprint View
view
: (optional, Array<{ type, size, position, props }>
) This describes the children and their structure
type
(required, WidgetType): The type of the child widget.size
(required,{ rows: number, cols: number }
): The number of rows and columns to be occupied by the child widget.position
(required,{ top: number, left: number }
): The row (top) and column(left) offset of the child widgetprops
(optional,Record<string, unknown>
): List of properties to be applied to the child widget as default.
Note: If this child needs to have its own children created at the same time, the blueprint of such a child needs to be provided as the blueprint
property in the props
.
Note: As described earlier, only the widgets of type CANVAS_WIDGET
can have children. Therefore, in most scenarios, the blueprint configuration will start with the CANVAS_WIDGET
, other nested children will be configured in the blueprint
prop of the CANVAS_WIDGET
. Please refer to the Form Widget example.
Note: The size
of a CANVAS_WIDGET
need not be defined, as this type of widget works independently and occupies all of the parent's size. As a result, the position
will also be {top: 0, left:0}
Widget Blueprint Operations
operations
: (optional, BlueprintOperation[]
) An array of operations to be performed to modify properties of the widget before they're shown on the canvas.
Type of BlueprintOperation
:
{ type: BlueprintOperationType, fn: BlueprintOperationFunction }
BlueprintOperationType
: These operations can be of three types:
- The operations to modify properties
BlueprintOperationTypes.MODIFY_PROPS
- The operations to add action trigger handlers
BlueprintOperationTypes.ADD_ACTION
- The operations to be performed, if a child widget is added to this widget.
BlueprintOperationTypes.CHILD_OPERATIONS
- Some widgets like the Table Widget, which have complex derived properties use a separate file for the derived property functions.
parseDerivedProperties.ts
helps load the functions from the associatedderived.js
as strings to use in binding the derived properties.
- Some constants are available via the Appsmith platform for widget developers to use in building widgets, which use some standard components. source code
- Similar to component constants, widget constants are separate sets of constants that widget developers can utilise.
- source1
- source2
- The Appsmith platform also provides utility functions to help develop widgets. source code
- A nice post by Hetu from the Appsmith team describes the evaluation logic in detail.
componentDidMount
andcomponentDidUpdate
lifecycle methods are discouraged when creating a widget. Other methods likegetDerivedPropertiesMap
can help derive related values before render.- Lazy loading a widget’s component is a good idea in many scenarios, especially, if a new library is being used to create this component.