Custom Components: Property layout in UI Builder

aasch
Mega Sage

Many OOTB Components in UI Builder use a specific layout with sections for their Component properties.

We can do the same for our custom Components built with ServiceNow CLI.

 

This is the property layout of a simple OOTB Button Component:

aasch_0-1781018431614.png

It has several properties and the sections "Identifier" and "Accessibility".

 

If we open the sys_uib_toolbox_component record of the OOTB Button Component, we can see the field "Config Layout" (config_layout) contains the following JSON data:

["label","variant","size","disabled",{"initialOpenState":true,"sectionType":"section","id":"identifier","title":"Identifier","children":["icon","animatedIcon"],"icon":"image-outline"},{"initialOpenState":true,"sectionType":"section","id":"accessibility","title":"Accessibility","children":["tooltipContent","configAria","landmark"],"icon":"accessibility-outline"}]

 

The documentation for the now-ui.json file  mentions a "configLayout" property. This property needs to be configured very similar to the JSON above for our custom Components, to achieve the same results.

 

Prerequisites

You're familiar with custom Components and their setup via SerivceNow CLI and the ui-component extension.

 

Assume we have the following basic Component:

import {createCustomElement} from '@servicenow/ui-core';
import snabbdom from '@servicenow/ui-renderer-snabbdom';
import styles from './styles.scss';

const view = (state, {updateState}) => (
	<div>
		<h1>Example Property Layout Component</h1>
		<p>My first property: {state.properties.myFirstProperty}</p>
		<p>My second property: {state.properties.mySecondProperty}</p>
	</div>
);

createCustomElement('x-191581-test-prop-layout-component', {
	renderer: {type: snabbdom},
	view,
	styles,
	properties: {
		"myFirstProperty": {
			default: "Hello world!",
			type: "string"
		},
		
		"mySecondProperty": {
			default: "Goodbye!",
			type: "string"
		}
	}
});

It has two properties: "myFirstProperty" and "mySecondProperty".

Both of them are interpolated into the view, which yields this in preview:

aasch_1-1781018847623.png

 

Preparing up now-ui.json

To make our two properties visible and changeable in UI Builder, we need to add them as properties in the now-ui.json file.
The file should look something like this:

{
  "components": {
    "x-191581-test-prop-layout-component": {
      "innerComponents": [],
      "uiBuilder": {
        "associatedTypes": [
          "global.core",
          "global.landing-page"
        ],
        "label": "Test Prop Layout Component",
        "tileIcon": "./tile-icon/generic-tile-icon.svg",
        "description": "A description of my component",
        "category": "primitives"
      },
      "properties": [
        {
          "name": "myFirstProperty",
          "label": "My first property",
          "readOnly": false,
          "required": true,
          "defaultValue": "Hello world!",
          "typeMetadata": {
            "schema": {
              "type": "string"
            }
          },
          "fieldType": "string"
        },
        {
          "name": "mySecondProperty",
          "label": "My second property",
          "readOnly": false,
          "required": true,
          "defaultValue": "Goodbye!",
          "typeMetadata": {
            "schema": {
              "type": "string"
            }
          },
          "fieldType": "string"
        }
      ]
    }
  },
  "scopeName": "x_191581_test_pr_0"
}

 

If we do it like this and deploy to our instance, it should look something like this in UI Builder:

aasch_2-1781019059541.png

Changing the values should be correctly reflected in the Component:

aasch_3-1781019144497.png

 

Setting up "configLayout"

The documentation describes the "configLayout" property states that it is a String property and it's described like this:

"Configuration for the configuration panel for component-name on UI Builder."

 

Unfortunately it's neither a String property, nor does the description describe in any way what the value of "configLayout" should be.

"configLayout" is currently of type String, but rather it's an object with a "layout" property, which contains the actual array of properties and sections (see OOTB Button config layout above).

 

First example:
We'd like to reverse the default property order. The default order is the order the properties appear in our now-ui.json file.

To reverse it, add the "configLayout" property to the "uiBuilder" property like this:

{
  "components": {
    "x-191581-test-prop-layout-component": {
      "innerComponents": [],
      "uiBuilder": {
        "associatedTypes": [
          "global.core",
          "global.landing-page"
        ],
        "label": "Test Prop Layout Component",
        "tileIcon": "./tile-icon/generic-tile-icon.svg",
        "description": "A description of my component",
        "category": "primitives",
        "configLayout": {
          "layout":
          [
            "mySecondProperty",
            "myFirstProperty"
          ]
        }
      },
      "properties": [
        {
          "name": "myFirstProperty",
          "label": "My first property",
          "readOnly": false,
          "required": true,
          "defaultValue": "Hello world!",
          "typeMetadata": {
            "schema": {
              "type": "string"
            }
          },
          "fieldType": "string"
        },
        {
          "name": "mySecondProperty",
          "label": "My second property",
          "readOnly": false,
          "required": true,
          "defaultValue": "Goodbye!",
          "typeMetadata": {
            "schema": {
              "type": "string"
            }
          },
          "fieldType": "string"
        }
      ]
    }
  },
  "scopeName": "x_191581_test_pr_0"
}

"My second property" should now appear first in the "Configure" tab of the Component in UI Builder:

aasch_4-1781019704789.png

 

To add a section, we simply add a section object the "configLayout" object and list all properties that should go in the section as its children.

A section object looks like this:

{
    "children": [
        "<propertyName1>",
        "<propertyName2>",
        "<propertyNameN>"
    ],
    "id": "unique_section_id",
    "initialOpenState": true,
    "order": 0,
    "sectionType": "section",
    "title": "My section name"
}

All of the properties are mandatory.


A serious trip up:

The "order" property doesn't seem to be listed anywhere in OOTB Component config layouts.
It's also not generated when creating Component properties via the Component editor in UI Builder.
It also will be completely ignored by UI Builder. The order of sections and properties is entirely dependent on their position in the layout array and not by the order property.

 

Moving on: If we want to now add a section to our custom demo Component, we can do something like this in the "configLayout" property:

{
    "layout": [
        {
            "children": [
                "mySecondProperty"
            ],
            "id": "section1",
            "initialOpenState": true,
            "order": 0,
            "sectionType": "section",
            "title": "A glorious section"
        },
        "myFirstProperty"
    ]
}

Which should result in this:

aasch_5-1781020270154.png

 

That's it!

 

Conclusion

It's possible to layout our custom Component's properties and put them into sections.
Be aware that the CLI can be very picky with formatting, missing attributes, etc.

 

Hope this helps 🙂

0 REPLIES 0