contributions/AppsmithWidgetDevelopmentGuide.md
React components can be connected to the Appsmith platform using the Widget Development APIs and registered to be available for use by Appsmith 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.
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
constants.tsx
icon.svg
widget/index.tsx
component/index.tsx
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 extends BaseWidget
config : Widget configuration (CONFIG described below)
index.tsThis 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(), where Widget is the default import from the widget/index.tsxname (required): The display name of this widget. This can contain spaces.iconSVG (required): IconSVG, where IconSVG is the import from the ./icon.svgneedsMeta (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 to true, 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.
src/WidgetsProvider/constants. See moreblueprint and enhancements 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 or null 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 when true, enables when false.updateWidgetProperty (void): Updates a single widget property
propertyPath: Path of the property to updatepropertyValue: Value to be setdeleteWidgetProperty (void): Deletes a particular widget property
batchUpdateProperty (void): Updates multiple properties. Arguments:
updates: Argument type BatchUpdatePropertyPayloadshouldReplay (boolean): If false, it will not be considered as a state to which an Appsmith developer can undo (cmd+z or ctrl+z). Default true.resetChildMetaProperty (void): Resets all meta properties of children of this widget. Arguments:
widgetId: Current widgetIdupdateWidgetMetaProperty (void): Different from updateWidgetProperty, 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<PropertyPaneConfig>``.
Example:
<p> </p>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<PropertyPaneConfig>``.
Example:
<p> </p>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<PropertyPaneConfig>``.
Example:
<p> </p>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 or undefined. 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 returns true 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 propertiesReturn
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 for updateHook and hidden, string[]): This lists the property paths which will be needed for computations in the hidden and updateHook 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 standard INPUT 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)ExampleProperties 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 for ValidationTypes.NUMBERmax(optional, number): Used to specify a maximum value for ValidationTypes.NUMBERnatural(optional, number): Used to validate a number as a natural number. Used with ValidationTypes.NUMBERdefault(optional, unknown): Used to provide a default value to an invalid or undefined 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 in ValidationTypes.TEXTallowedKeys(optional, Array<Record<string, unknown>>): Array of configurations for the allowed keys in ValidationTypes.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 validationallowedValues(optional, unknown[]): An array containing the set of allowed values for ValidationTypes.ARRAYchildren(optional, ValidationConfig): Validation configuration for entries in ValidationTypes.OBJECT_ARRAYfn(optional, (value: unknown, props: any, _?: any, moment?: any) => ValidationResponse): The function used to validation in ValidationTypes.FUNCTION
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 configurationsexpected (required for ValidationTypes.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 to true, values in ValidationTypes.TEXT, will not be cast to a string before validating.ignoreCase (optional, boolean): If set to true, keys will be matched while ignoring case in allowedKeys parameter of the ValidationTypes.OBJECT.ValidationTypes.FUNCTION is meant to be used sparingly, and as an escape hatch when the other ValidationTypes do not fit the requirements of validation.ValidationResponseA 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:
BlueprintOperationTypes.MODIFY_PROPSBlueprintOperationTypes.ADD_ACTIONBlueprintOperationTypes.CHILD_OPERATIONSparseDerivedProperties.ts helps load the functions from the associated derived.js as strings to use in binding the derived properties.componentDidMount and componentDidUpdate lifecycle methods are discouraged when creating a widget. Other methods like getDerivedPropertiesMap can help derive related values before render.