Building forms in OutSystems is incredibly fast. You simply define a structure, add a form element to the canvas, and drag and drop the individual fields into the form. This is excellent for static forms linked to data structures, but only developers can create these forms, and after they're built and tested, the application must be redeployed to production.
In some situations, you might need to build a form dynamically, along with its data model, or even let an end-user define a form and its elements while using the application. Assessments or surveys are good examples of such user-defined forms. Additionally, you could consider dynamically creating a form from an AI model operation result.
In this article, we explore how to implement my Runtime Forms component available on ODC Forge. The library allows you to dynamically describe and render a form. This approach is also called declarative forms, where you specify what the form should look like and how it should behave in a configuration (in this case, a structure), instead of placing individual input elements on the canvas like with static forms.
Demo Application
This article includes a demo application called "Runtime Forms Demo," available on ODC Forge.
This demo depends on:
- Runtime Forms - This is the main library you can use and customize for your own applications. It offers a single widget to render a declarative form.
The library you downloaded from ODC Forge includes a single UI widget for rendering a declarative form. Think of it as a starting point that you can improve and customize for your own needs.

It supports the following features:
Renders various input elements based on parameters (Fields) that describe them.
Populates data (Data) into input elements from a JSON document.
Validates the form on submission using HTML5 validation attributes.
Sends form data as a JSON document upon submission (OnSubmit).
The form elements you can use with the widget are limited to the following input types:
Text Inputs
Text - A single-line text field. This is the default value for an input element.
Textarea - A multi-line text field.
Password - A single-line text field where the input is obscured to protect sensitive information.
Email - A field specifically for entering one or more email addresses. Validation ensures that the text entered is a valid e-mail address.
Search - A single-line text field for entering search queries. It may include a control to clear the entered text.
Tel - A field for entering a telephone number. Unlike email, it doesn't enforce a specific syntax, but it may trigger a numeric keypad on mobile devices.
Url - A field for entering a URL. The browser may provide validation to ensure the text is in a valid URL format.
Date and Time Inputs
date - A control for entering a date (year, month, and day).
time - A control for entering a time (hour and minute).
datetime-local - A control for entering both a date and time, without time zone information.
month - A control for entering a month and year.
week - A control for entering a week and year.
Numeric Inputs
- number - A field for entering a number.
Selection Inputs
All input elements are displayed in the order specified by the Fields input parameter of the widget.
Field Configurations and Validations
Input field configurations and validations are divided into two parts: a common set of configuration elements that apply to all supported form elements, and type-specific settings that apply only to individual form element types.
Common
The following settings apply to all types:
Name - The name attribute of the form element. This name also becomes the attribute name of the JSON data document you receive when you submit the form.
Type - The input element's type attribute. The FieldType static entity provides the supported element types as described above.
Label - If present, the widget adds an extra <label> tag for the form element.
Text - If present, this text is displayed right above the form element. You can use it to add extra descriptions or guidance for the form element.
Placeholder - If present, it sets the placeholder attribute of the form element.
IsRequired - If set to True, it adds the required attribute to the form element, making user input necessary.
IsDisabled - If set to True, it adds the disabled attribute to the form element. When the form is submitted, data from disabled elements is excluded.
IsReadOnly - If set to True, it adds the readonly attribute to the form element. Data from readonly elements is included when the form is submitted.
HasAutoFocus - Sets the autofocus attribute for the form element. Ensure that only one element has autofocus.
TabIndex - Defaults to 0. When set, this configures the tab order of the element.
Type-specific
Type-specific settings are found in the Config object. Depending on the chosen input type, the following settings apply.
For text, textarea, password, email, search, tel and url the following settings apply:
MinLength - Specifies the minimum number of characters the user must enter for the input to be considered valid.
MaxLength - Specifies the maximum number of characters the user can enter into the input field.
Pattern - Specifies a regular expression that the input field's value is checked against. It allows for complex validation rules.
Autocomplete - Specifies whether a browser should automatically complete the input based on values the user has entered previously. Can be set to "on" or "off".
Rows (only applicable to textarea) - The number of rows of the multi-line text input element.
For date, time, datetime-local, month and week:
For number:
Min - Specifies the minimum allowed value for the input.
Max - Specifies the maximum allowed value for the input.
Step - Specifies the legal number intervals (e.g., step="2" allows 0, 2, 4...). any allows any value.
For radio and checkbox:
IsChecked - A boolean attribute that specifies if a checkbox or radio button should be selected by default when the page loads.
Options (Radio only) - A list of Label/Value pairs for the radio options to select from.
Most of the settings above are related to validation, and the library uses the browser's built-in form validation. You can read more about this client-side form validation on MDN.
Applying and Submitting Data
The Data input parameter lets you add a JSON document as a string. The library attempts to apply the attribute values to the corresponding input elements based on the name.
Consider the following form:
A text field named fullName
A checkbox field named isMember
A radio field shirtSize with the Label/Value pairs [Small - S], [Large - L], and [X-Large - XL]
The JSON document to apply all values would look like this:
{
"fullName": "Stefan Weber",
"isMember": true,
"shirtSize": "XL"
}
Similarly, when you submit the form, you will receive an equivalent JSON document as the OnSubmit payload.
Library Limits
By the time of writing the Runtime Forms library does not support
💡
If you plan to use this library and need more features, please write a post on the OutSystems Forum.
Demo Walkthrough
Let's take a closer look at how this works. In ODC Studio, open the Runtime Forms Demo application.
In the Logic tab, open the BuildSampleForm server action. This action is designed to create individual form elements using the FieldDefinition structure. It returns a list of FieldDefinition that serve as input parameters for the library's RuntimeForm widget.

Check the various configurations of the field elements.
In the Interface tab open the Run screen.

The GetFormDefinition data action executes the BuildSampleForm server action. The result of the data action is bound to the Fields input parameter of the RuntimeForm widget.
The local DataEntry variable is linked to the JSON Data textarea on the right side of the screen. When you click the Apply Data button (triggering the ApplyDataOnClick client action), the content of this variable is assigned to the DataSubmitted variable, which is bound to the Data input parameter of the widget.
💡
The above is necessary to prevent rerenders of the form elements while typing JSON data. Please also note that the RuntimeForm widget is wrapped in an If and only rendered after the GetFormDefinition action ran.
When running the demo you will see the following screen.

Hit the Apply Data button for applying the provided JSON data to the form.
Leave the Company Mail Address empty and click the Submit button. Note the validation error message below the mail address.
Enter a invalid value into the mail address field e.g. me@ and note the validation message.
Fill in all required fields and click the Submit button. Note the JSON data in the Last Submitted JSON data area.
Add and modify Field definitions in the BuildSampleForm server action.
Library Modifications
As mentioned above, you may need to adjust the library to fit your needs, such as adding custom client-side validations or additional form elements. Take a look at the RuntimeForms library, especially the following:
RuntimeForm widget
ValidateForm client action - Validates all non-disabled field elements. If you want to customize or extend browser-based validation, this is where you can do it.
PopulateFormData client action - Fills the individual field elements with the provided data.
SubmitOnClick - Triggers the OnSubmit event with the form data as the payload.
RuntimeFormField
- ApplyFieldConfiguration client action - This action applies type-specific field attributes to the elements (e.g., required, minLength, etc.).
Summary
This article introduces the Runtime Forms library, available on ODC Forge, which enables dynamic form creation in OutSystems Developer Cloud applications. Unlike static forms, Runtime Forms allow developers or even end-users to define and render forms on-the-fly using a declarative approach. The component supports various input types and validations.
I hope you enjoyed it and would appreciate your feedback.