Extension
The extension component can be used to write your own component using HTML and JavaScript.
Properties
The form definition can include the following properties to control how the Extension component behaves. Each property corresponds to a the name of a JavaScript function that is invoked at a specific stage in the component’s lifecycle.
These functions correspond to those used when creating Form.io custom components.
It is not necessary to implement every function. If a function is not provided, the component will fall back to its default behavior. However, renderFn and attachFn are typically required to get a functioning component.
| Name | Description | Function signature |
|---|---|---|
| constructorFn | Called when the component has been instantiated. This is useful to define default instance variable values. | constructor(component, options, data) |
| initFn | Called immediately after the component has been instantiated to initialize the component. | init() |
| renderFn | This method is used to render a component as an HTML string. It must return a valid HTML string. | render(): string |
| attachFn | The attach method is called after "render" which takes the rendered contents from the render method (which are by this point already added to the DOM), and then "attach" this component logic to that html. This is where you would load any references within your templates (which use the "ref" attribute) to assign them to the "this.refs" component variable. | attach(element): Promise |
| detachFn | Called when the component has been detached. This is where you would destroy any other instance variables to free up memory. Any event registered with "addEventListener" will automatically be detached so no need to remove them here. | detach(): Promise |
| destroyFn | Called when the component has been completely "destroyed" or removed form the renderer. | destroy(): Promise |
| normalizeValueFn | A very useful method that will take the values being passed into this component and convert them into the "standard" or normalized value. For example, this could be used to convert a string into a boolean, or even a Date type. | normalizeValue(value, flags = {}): value |
| getValueFn | Returns the value of the "view" data for this component. | getValue(): value |
| setValueFn | Sets the value of both the data and view of the component (such as setting the <input> value to the correct value of the data). This is most commonly used externally to set the value and also see that value show up in the view of the component. If you wish to only set the data of the component, like when you are responding to an HTML input event, then updateValue should be used instead since it only sets the data value of the component and not the view. | setValue(value, flags = {}): Boolean |
| updateValueFn | Similar to setValue, except this does NOT update the "view" but only updates the data model of the component. | updateValue(value, flags = {}): Boolean |
Example
This example demonstrates a custom numeric input component integrated into a Simian application, combining:
- Python backend logic
- Custom JavaScript frontend extension
- JSON-based form definition
The application renders a form with:
- A custom counter component (with + and − buttons)
- A button that triggers a backend event

When the button is clicked, the current value of the custom component is sent to the backend, printed, and then reset to 0.
Python Backend
def gui_init(meta_data: dict) -> dict:
form = Form(from_file=__file__)
return {"form": form}
- Loads the JSON form definition from the file
- Creates a Form instance
- Returns it to the frontend
def gui_event(meta_data: dict, payload: dict) -> dict:
value, _ = utils.getSubmissionData(payload, "custom")
print(value)
newValue = 0
utils.setSubmissionData(payload, "custom", newValue)
return payload
Handles events from the front-end, in this case the button click:
- Retrieves the value of the "custom" field
- Prints it to the console
- Sets the value to 0
- Returns the updated payload
Custom JavaScript
The custom JavaScript code defines a custom Extension component.
function customRender() {
let value = this.dataValue;
return `<div>
<button ... ref="minus">
<i class="bi bi-dash-square"></i>
</button>
<input type="number" ref="number" value=${value} />
<button ... ref="plus">
<i class="bi bi-plus-square"></i>
</button>
</div>`;
}
Renders the following HTML elements:
- ➖ Minus button
- 🔢 Numeric input field, the value is set to the submission data
- ➕ Plus button
async function customAttach(element) {
this.loadRefs(element, {
minus: 'single',
number: 'single',
plus: 'single'
});
this.refs.minus.addEventListener('click', () =>
this.setValue(this.getValue() - 1)
);
this.refs.number.addEventListener('input', (event) =>
this.setValue(event.target.valueAsNumber)
);
this.refs.plus.addEventListener('click', () =>
this.setValue(this.getValue() + 1)
);
}
The customAttach function loads the references defined in the customRender function (ref="..."), and attaches listeners to the elements.
- Clicking ➖ decreases the value by one
- Clicking ➕ increases the value by one
- Typing updates the value in the data model
function customGetValue() {
return this.refs.number.valueAsNumber;
}
- Returns the numeric value of the input element.
function customSetValue(value, flags) {
this.refs.number.value = value;
}
- Updates the input field.
JSON Form Definition
{
"components": [
{
"label": "Custom",
"type": "extension",
"key": "custom",
"renderFn": "customRender",
"attachFn": "customAttach",
"getValueFn": "customGetValue",
"setValueFn": "customSetValue",
"defaultValue": 100
},
{
"label": "Click",
"type": "button",
"key": "btn",
"action": "event",
"event": "click"
}
]
}
The first component is the custom Extension component:
- Type: "extension"
- Default value: 100
- Defines which custom JavaScript functions to use to specify its behavior
The second component is a Button:
- Type: "button"
- Action: "event"
- Event name: "click"
- When clicked it triggers
gui_eventin Python.