Skip to main content
The UI Schema defines how to render a dynamic form — the layout structure, controls, conditional visibility rules, and custom options. It follows the JSON Forms UI Schema specification.

Structure

A UI Schema is a tree of elements. Each element has a type that determines how it behaves:
  • Layouts — Container elements that organize other elements
  • Controls — Elements that render input fields bound to schema properties
{
  "type": "VerticalLayout",
  "elements": [
    {
      "type": "Control",
      "scope": "#/properties/firstName",
      "label": "First Name"
    },
    {
      "type": "Control",
      "scope": "#/properties/lastName",
      "label": "Last Name"
    }
  ]
}

Layouts

Layouts organize controls and other layouts into a visual structure.

VerticalLayout

Arranges elements vertically, one below the other.
{
  "type": "VerticalLayout",
  "elements": [
    { "type": "Control", "scope": "#/properties/firstName" },
    { "type": "Control", "scope": "#/properties/lastName" }
  ]
}

HorizontalLayout

Arranges elements horizontally, side by side.
{
  "type": "HorizontalLayout",
  "elements": [
    { "type": "Control", "scope": "#/properties/firstName" },
    { "type": "Control", "scope": "#/properties/lastName" }
  ]
}

Group

Groups related controls together with an optional label.
{
  "type": "Group",
  "label": "Personal Information",
  "elements": [
    { "type": "Control", "scope": "#/properties/firstName" },
    { "type": "Control", "scope": "#/properties/lastName" }
  ]
}

Categorization

Organizes content into tabs or wizard-style steps. A Categorization contains multiple Category elements, each representing a step in the form.
{
  "type": "Categorization",
  "elements": [
    {
      "type": "Category",
      "label": "Personal Info",
      "elements": [
        { "type": "Control", "scope": "#/properties/personalInfo/properties/firstName" },
        { "type": "Control", "scope": "#/properties/personalInfo/properties/lastName" }
      ]
    },
    {
      "type": "Category",
      "label": "Contact Info",
      "elements": [
        { "type": "Control", "scope": "#/properties/contactInfo/properties/email" },
        { "type": "Control", "scope": "#/properties/contactInfo/properties/phone" }
      ]
    }
  ]
}
Categories correspond to steps in the schema. Each Category typically maps to a root-level schema property, enabling progressive disclosure as users complete each step.

ListWithDetail

Renders an array as a master-detail view — a list of items on one side and a detail form for the selected item.
{
  "type": "ListWithDetail",
  "scope": "#/properties/addresses",
  "options": {
    "detail": {
      "type": "VerticalLayout",
      "elements": [
        { "type": "Control", "scope": "#/properties/street" },
        { "type": "Control", "scope": "#/properties/city" }
      ]
    }
  }
}

Controls

Controls render input fields and bind them to schema properties.

Control

The Control element renders an input based on the schema type at the specified scope.
{
  "type": "Control",
  "scope": "#/properties/email",
  "label": "Email Address"
}
PropertyDescription
scopeJSON Pointer to the schema property (e.g., #/properties/email)
labelDisplay label for the control (optional — derived from schema if omitted)
optionsCustom options to modify control behavior
The renderer automatically selects the appropriate input type based on the schema:
Schema TypeRendered As
stringText input
string + format: "date" (schema)Date picker
string + options.format: "postal-code"Postal code input
string + enumDropdown/select
numberNumber input
booleanCheckbox or toggle
arrayList with add/remove

Rules

Rules control the visibility and enabled state of elements based on data conditions.
{
  "type": "Control",
  "scope": "#/properties/employerName",
  "rule": {
    "effect": "SHOW",
    "condition": {
      "scope": "#/properties/employmentStatus",
      "schema": { "const": "employed" }
    }
  }
}

Effects

EffectDescription
SHOWShow the element when condition is true, hide otherwise
HIDEHide the element when condition is true, show otherwise
ENABLEEnable the element when condition is true, disable otherwise
DISABLEDisable the element when condition is true, enable otherwise

Conditions

A condition specifies a scope (the property to evaluate) and a schema that the value must match.
{
  "condition": {
    "scope": "#/properties/country",
    "schema": { "enum": ["US", "CA"] }
  }
}
Common condition patterns:
PatternSchema
Equals a value{ "const": "value" }
One of many values{ "enum": ["a", "b", "c"] }
Not empty{ "minLength": 1 }

Options

The options property on controls allows you to customize behavior. These are standard JSON Forms options.

Array options

Options for array controls:
OptionDescription
showSortButtonsShows buttons to reorder items
elementLabelPropProperty to use as the label for each item in a list
disableAddPrevents adding new items (renderer-specific)
disableRemovePrevents removing items (renderer-specific)
{
  "type": "Control",
  "scope": "#/properties/documents",
  "options": {
    "elementLabelProp": "name",
    "showSortButtons": true
  }
}

readonly

Renders the control as read-only.
{
  "type": "Control",
  "scope": "#/properties/accountId",
  "options": {
    "readonly": true
  }
}

detail

For ListWithDetail layouts, specifies the UI Schema for the detail view.
{
  "type": "ListWithDetail",
  "scope": "#/properties/items",
  "options": {
    "detail": {
      "type": "VerticalLayout",
      "elements": [...]
    }
  }
}

Custom options

The Enterprise API Suite extends JSON Forms with custom options for specific use cases.

data

Specifies a data source for populating select options dynamically. The data object defines where to fetch options from and how to filter them.
{
  "type": "Control",
  "scope": "#/properties/country",
  "options": {
    "data": {
      "source": "countries",
      "exclude": {
        "restrictions": [
          {
            "scope": "citizenship"
          }
        ]
      }
    }
  }
}
PropertyDescription
data.sourceThe data source to fetch options from.
Available sources: "countries" (List countries) and "subdivisions" (Get country, returns subdivisions for a given country).
data.excludeOptional filter to exclude values from the data source
data.exclude.restrictionsArray of restrictions to filter values from the data source
data.exclude.restrictions[].scopeThe restriction scope (e.g., citizenship, residence, geolocation, phone)

format

Specifies custom display formats for controls that are not covered by the standard JSON Schema format keyword. Standard formats like date are defined in the JSON Schema and handled natively by renderers.
{
  "type": "Control",
  "scope": "#/properties/address/properties/postalCode",
  "options": {
    "format": "postal-code"
  }
}
FormatDescription
postal-codeRenders an input optimized for postal codes, with formatting and validation rules that may vary by country

rules (validation)

Defines client-side validation rules on a control. These rules allow you to enforce constraints that go beyond standard JSON Schema validation, such as age thresholds relative to the current date.
These validation rules are defined in options.rules on individual controls and are distinct from the visibility rules (rule with effect and condition) that control element visibility.
{
  "type": "Control",
  "scope": "#/properties/birthdate",
  "options": {
    "rules": [
      {
        "rule": "difference-greater-than-or-equal-to-threshold",
        "threshold": {
          "limit": 18,
          "unit": "years"
        }
      },
      {
        "rule": "difference-less-than-or-equal-to-threshold",
        "threshold": {
          "limit": 100,
          "unit": "years"
        }
      }
    ]
  }
}
In this example, the date must be at least 18 years ago and at most 100 years ago, effectively restricting the input to valid adult birthday dates.
PropertyDescription
rules[].ruleThe validation rule type. Available rules: difference-greater-than-or-equal-to-threshold, difference-less-than-or-equal-to-threshold.
rules[].threshold.limitThe numeric limit for the threshold
rules[].threshold.unitThe unit for the threshold (e.g., "years")

dependsOn

Declares that a control depends on the value of one or more other controls. When a dependency value changes, the dependent control should update its available options or validation accordingly.
{
  "type": "Control",
  "scope": "#/properties/address/properties/subdivision",
  "options": {
    "data": {
      "source": "subdivisions"
    },
    "dependsOn": [
      {
        "name": "country",
        "scope": "#/properties/address/properties/country"
      }
    ]
  }
}
In this example, the subdivision field depends on the selected country — when the country changes, the list of available subdivisions is updated.
PropertyDescription
dependsOnArray of field dependencies
dependsOn[].nameThe logical name of the dependency (e.g., "country")
dependsOn[].scopeJSON Pointer to the dependency’s schema property
Dependencies can also be chained. For example, a postal code field can depend on both country and subdivision:
{
  "type": "Control",
  "scope": "#/properties/address/properties/postalCode",
  "options": {
    "format": "postal-code",
    "dependsOn": [
      {
        "name": "country",
        "scope": "#/properties/address/properties/country"
      },
      {
        "name": "subdivision",
        "scope": "#/properties/address/properties/subdivision"
      }
    ]
  }
}

Next steps

Rendering

Implementation guidance and best practices.