Skip to main content

Using JSON Forms

This guide shows you how to implement common patterns and advanced features with JSON Forms in your configuration wizard.

Before you begin, make sure you understand the basics covered in What are JSON Forms?.

Creating layouts

UI elements can be laid out horizontally or vertically, and layouts can be nested to create sophisticated form structures.

Nested layouts

In this example, a HorizontalLayout contains two VerticalLayout elements. The second vertical layout element is a Group type layout, which adds a container and label around the vertically organized input elements.

Nested Layouts
{
"type": "HorizontalLayout",
"elements": [
{
"type": "VerticalLayout",
"elements": [
{
"type": "Control",
"scope": "#/properties/companyName"
},
{
"type": "Control",
"scope": "#/properties/companyDescription"
}
]
},
{
"type": "Group",
"label": "Additional Data",
"elements": [
{
"type": "Control",
"label": "Employee Count",
"scope": "#/properties/numEmployees"
},
{
"type": "Control",
"scope": "#/properties/continent"
}
]
}
]
}

Screenshot of nested layouts in JSON forms(maxWidth: 600px)

See example in playground

Building dropdown menus

You can present users with dropdown menus of prepopulated options using enum or oneOf properties in your schema.

Using enum for dropdowns

An enum property creates a dropdown menu from a set of string values:

Example using enum
{
"type": "object",
"properties": {
"continent": {
"type": "string",
"enum": [
"North America",
"South America",
"Europe",
"Asia",
"Africa",
"Australia"
]
}
}
}

Screenshot of dropdown menu in JSON forms(maxWidth: 600px)

When someone selects "North America", the integration receives { continent: "North America" }.

Using oneOf for custom values

oneOf is useful when you want to show human-readable labels in the UI but return different values to the integration.

In this example, users see full continent names but the integration receives two-letter codes:

Example using oneOf
{
"type": "object",
"properties": {
"continent": {
"type": "string",
"oneOf": [
{
"title": "North America",
"const": "NA"
},
{
"title": "South America",
"const": "SA"
},
{
"title": "Europe",
"const": "EU"
},
{
"title": "Asia",
"const": "AS"
},
{
"title": "Africa",
"const": "AF"
},
{
"title": "Australia",
"const": "AU"
}
]
}
}
}

When someone selects "North America", the integration receives { continent: "NA" }.

Working with arrays

Arrays allow users to specify values for multiple copies of a set of fields.

In this example, two fields (channel and notifications) are properties of an object that can be repeated within a slackChannels array:

Example of an array
{
"type": "array",
"items": {
"type": "object",
"properties": {
"channel": {
"type": "string"
},
"notifications": {
"type": "string",
"enum": [
"Opportunity Created",
"Opportunity Updated",
"Opportunity Closed/Won",
"Opportunity Closed/Lost"
]
}
}
}
}

Adding sort buttons

You can enable sort buttons in the uiSchema to let users reorder array elements:

Example UI Schema
{
"type": "VerticalLayout",
"elements": [
{
"type": "Control",
"scope": "#",
"options": {
"showSortButtons": true
}
}
]
}

Screenshot of a basic array in JSON forms(maxWidth: 600px)

The integration receives arrays as a list of objects:

[
{
"channel": "#sales-opportunities",
"notifications": "Opportunity Created"
},
{
"channel": "#sales-opportunities",
"notifications": "Opportunity Updated"
},
{
"channel": "#sales-opportunities-won",
"notifications": "Opportunity Closed/Won"
},
{
"channel": "#sales-opportunities-lost",
"notifications": "Opportunity Closed/Lost"
}
]
See example in playground

Using accordion layout for arrays

Arrays can be presented in an Accordion layout to save space in the configuration wizard. Specify which field should be used for accordion labels with the elementLabelProp option:

Accordion layout UI Schema
{
"type": "VerticalLayout",
"elements": [
{
"type": "Control",
"scope": "#",
"options": {
"layout": "Accordion",
"elementLabelProp": "channel",
"showSortButtons": true
}
}
]
}

Screenshot of a basic array in JSON forms(maxWidth: 600px)

See example in playground

Building field mappers with arrays

Arrays are especially useful when building data mapping UIs. See the Building a Field Mapper Data Source tutorial for a complete example of how to build a field mapper between custom fields in Salesforce and your app.

See example in playground

Showing and hiding fields conditionally

You can show or hide fields based on the value of other fields using UI rules. A rule contains a condition that determines whether an effect should be applied.

In this example, the convertToUSD input field only appears when the country field is not United States:

{
"type": "Control",
"scope": "#/properties/convertToUSD",
"options": {
"toggle": true
},
"rule": {
"effect": "SHOW",
"condition": {
"scope": "#/properties/country",
"schema": {
"not": {
"const": "United States"
}
}
}
}
}
See example in playground

For more rule examples, see the JSON Forms rules documentation.

Validating user input

You can validate what users enter into input fields by adding validation properties to your schema.

Common validation properties

  • format: Built-in formats like email, uri, ipv4, date, time, date-time
  • minimum and maximum: Numeric range validation
  • minLength and maxLength: String length validation
  • pattern: Regular expression pattern matching
  • formatMinimum and formatMaximum: Date range validation
Examples of input validation
{
"type": "object",
"properties": {
"stringMinLength": {
"type": "string",
"minLength": 5,
"description": "Please enter a string with at least 5 characters"
},
"stringMaxLength": {
"type": "string",
"maxLength": 5,
"description": "Please enter a string with at most 5 characters"
},
"email": {
"type": "string",
"format": "email",
"description": "Please enter a valid email address."
},
"uri": {
"type": "string",
"format": "uri",
"description": "Please enter a valid URI."
},
"ipv4": {
"type": "string",
"format": "ipv4",
"description": "Please enter a valid IPv4 address."
},
"regex": {
"type": "string",
"pattern": "^(\\([0-9]{3}\\))?[0-9]{3}-[0-9]{4}$",
"description": "Please enter a valid phone number in the form (123)456-7890."
},
"intOneTen": {
"type": "integer",
"minimum": 1,
"maximum": 10,
"description": "Please enter an integer between 1 and 10."
},
"startDate": {
"type": "string",
"format": "date",
"description": "Please enter a date between the first and last day of the current month.",
"formatMinimum": "2023-08-01",
"formatMaximum": "2023-08-31"
}
},
"required": [
"stringMinLength",
"stringMaxLength",
"email",
"uri",
"ipv4",
"regex",
"intOneTen",
"startDate"
]
}
See example in playground

For custom validation rules beyond the built-in options, see JSON Form Validation.

Adding autocomplete to dropdown inputs

You can provide autocomplete functionality for oneOf dropdown menus by enabling the autocomplete option in the uiSchema:

{
"options": {
"autocomplete": true
}
}

In this example, typing "Cor" will match both "Acme Corp" and "Umbrella Corp":

Screenshot of a autocomplete in dropdown menu in JSON forms(maxWidth: 650px)

See example in playground

Customizing field mapper layouts

The Building a Field Mapper Data Source tutorial demonstrates a basic field mapper. You can control the field mapper layout by using a custom options.detail specification.

To create a custom layout:

  1. Set options.layout to "Accordion"
  2. Define your custom layout structure using options.detail
Custom layout UI Schema
{
"type": "Control",
"label": "Salesforce Lead <> Acme Sale Field Mapper",
"scope": "#",
"options": {
"layout": "Accordion",
"detail": {
"type": "HorizontalLayout",
"elements": [
{
"type": "Control",
"scope": "#/properties/source",
"options": {
"autocomplete": true
}
},
{
"type": "Control",
"scope": "#/properties/destination",
"options": {
"autocomplete": true
}
}
]
}
}
}

Screenshot of a custom field mapper in JSON forms(maxWidth: 650px)

See example in playground

Creating forms with multiple tabs

JSON Forms can display content across multiple tabs using categorization.

Create tabs with a "type": "Categorization" layout in your uiSchema. Each category becomes a tab with its own label:

Tabs UI Schema
{
"type": "Categorization",
"elements": [
{
"type": "Category",
"label": "Contacts",
"elements": [
{
"type": "Control",
"scope": "#/properties/contacts"
}
]
},
{
"type": "Category",
"label": "Leads",
"elements": [
{
"type": "Control",
"scope": "#/properties/leads"
}
]
},
{
"type": "Category",
"label": "Opportunities",
"elements": [
{
"type": "Control",
"scope": "#/properties/opportunities"
}
]
}
]
}

Screenshot of a field mapper with tabs in JSON forms(maxWidth: 650px)

See example in playground

This is particularly useful for complex field mappers that handle multiple object types.

Using JSON Forms in custom components

If your form is static and doesn't depend on fetching data from third-party apps, you can provide schema and uiSchema directly to the JSONForms component.

For forms that need to present dropdown menus or other fields populated from third-party apps, build the form in a custom component using the custom component SDK. See the JSON Forms data sources documentation for details.

Pre-filling forms with default data

Your custom JSON Forms data sources can include a data property in addition to schema and uiSchema. When you include data, the form is pre-filled with the values you provide.

Handling form data updates

Consider a config wizard with this flow:

  • Page 1: Connect to Microsoft SharePoint with OAuth 2.0
  • Page 2: Select a SharePoint site from a dropdown menu
  • Page 3: Display a JSON form tailored to the selected site, with default data from that site

This works fine when a user first completes the wizard. However, if they reopen the config wizard and select a different site on page 2, you need to handle the stale data from their previous selection.

Configuring data source reset behavior

By default, if a config variable has user-supplied data, the default data your config variable generates is ignored in favor of the user's previous selections.

You can override this behavior in the config wizard designer by navigating to Data Source Reset within your JSON Forms config variable:

Configure data source resetting in config wizard(maxWidth: 650px)

Choose one of these options:

  • Never: Uses the default behavior and displays the user's previous data

  • Prompt: Notifies the end user that their data may be stale and gives them the option to reset the form to the default values supplied by your data source

    Configure data source resetting in config wizard(maxWidth: 850px)

  • Always: Automatically overrides the user's previous selection with your data source's default data when the data source inputs change

Next steps

You now know how to implement common JSON Forms patterns. Continue learning with these resources: