Custom Object Layouts

Layouts allow you to control how the properties of a Custom Object are displayed when viewing or editing instances of that object. Without a layout, all properties are displayed in a simple vertical list. With a layout, you can organize properties into sections, tabs, and multi-column arrangements.

Layout Settings

Each layout has the following settings:

Name

A unique name for this layout (required). This name is shown to users when selecting a layout.

Description

An optional description explaining when this layout should be used.

Ordinal

Controls the display order of layouts. Lower numbers appear first.

Active

Only active layouts are available to users. Inactive layouts are hidden.

Layout Assignments

Layouts can be assigned to specific users based on their role:

Allow All Users

If set to Yes, any user that can view the project can use this layout. Role assignments are ignored.

Allow Project Owner

If set to Yes, the Project Owner can use this layout in addition to any assigned roles.

Assigned Roles

Select which Project Roles can use this layout. Users with these roles will see this layout as an option.

When a user has access to multiple layouts, they can choose which one to use when viewing or editing custom object instances.

Layout JSON Format

The layout structure is defined using JSON. If no JSON is provided (empty), all properties are displayed in a simple vertical list.

Node Types

The layout JSON consists of nested nodes. Each node must have a type property. The available node types are:

Container Nodes (can contain other nodes):

  • VerticalLayout - Arranges children vertically, one below another

  • HorizontalLayout - Arranges children horizontally in columns

  • Section - A collapsible section with a header label

  • Tabs - Organizes children as tabbed panels

Leaf Nodes (display content):

  • Field - Displays a property field

  • Content - Displays static HTML content (headings, text, separators, etc.)

Basic Structure

A simple vertical layout with three fields:

{
  "type": "VerticalLayout",
  "children": [
    {"type": "Field", "fieldId": "Name"},
    {"type": "Field", "fieldId": "Description"},
    {"type": "Field", "fieldId": "Status"}
  ]
}

Field Node

Field nodes reference a property by name using the fieldId property:

{"type": "Field", "fieldId": "PropertyName"}

The fieldId must match the name of an active property definition for the custom object. Fields not included in the layout will appear in an "Other Fields" section.

Content Node

Content nodes display static HTML content such as headings, help text, or separators. Use the html property to specify the content:

{"type": "Content", "html": "<h4>Section Title</h4><p>Enter details below.</p>"}

Content nodes can also be used as spacers in horizontal layouts by using an empty html value:

{
  "type": "HorizontalLayout",
  "children": [
    {"type": "Field", "fieldId": "FirstName", "columns": 5},
    {"type": "Content", "html": "", "columns": 2},
    {"type": "Field", "fieldId": "LastName", "columns": 5}
  ]
}

In a HorizontalLayout, Content nodes must include a columns property like other children.

Allowed HTML tags: b, div, hr, i, u, li, sup, br, ol, ul, font, small, h1, h2, h3, h4, p, a, span, sub, em, table, thead, tbody, th, tr, td.

For safety, HTML content is sanitized before display. Script tags and other potentially unsafe content will be removed.

Horizontal Layout

Use HorizontalLayout to arrange fields side by side. Each child must specify a columns value:

{
  "type": "HorizontalLayout",
  "children": [
    {"type": "Field", "fieldId": "FirstName", "columns": 6},
    {"type": "Field", "fieldId": "LastName", "columns": 6}
  ]
}

The total columns should not exceed 12. In this example, both fields take up half the width (6 + 6 = 12).

Section

Sections group related fields with a labeled header:

{
  "type": "Section",
  "label": "Contact Information",
  "children": [
    {"type": "Field", "fieldId": "Email"},
    {"type": "Field", "fieldId": "Phone"}
  ]
}

Tabs

Tabs organize content into tabbed panels. Each child must have a label property for the tab title:

{
  "type": "Tabs",
  "children": [
    {
      "type": "VerticalLayout",
      "label": "General",
      "children": [
        {"type": "Field", "fieldId": "Name"},
        {"type": "Field", "fieldId": "Description"}
      ]
    },
    {
      "type": "VerticalLayout",
      "label": "Details",
      "children": [
        {"type": "Field", "fieldId": "Status"},
        {"type": "Field", "fieldId": "Priority"}
      ]
    }
  ]
}

Read-Only Fields

You can mark fields or entire containers as read-only by adding "read_only": true to a node. Read-only fields are displayed with a lock icon and cannot be edited by the user, even if they have edit permissions. This is useful for creating "review" layouts where most fields should be locked.

Making a single field read-only:

{"type": "Field", "fieldId": "ApprovedBy", "read_only": true}

Making all fields in a container read-only:

{
  "type": "Section",
  "label": "Approved Details",
  "read_only": true,
  "children": [
    {"type": "Field", "fieldId": "ApprovedBy"},
    {"type": "Field", "fieldId": "ApprovalDate"}
  ]
}

Overriding a parent's read-only setting:

A child node can explicitly set "read_only": false to override a parent container's read-only setting. In this example, the "Status" field is editable even though the parent container is read-only:

{
  "type": "VerticalLayout",
  "read_only": true,
  "children": [
    {"type": "Field", "fieldId": "Name"},
    {"type": "Field", "fieldId": "Description"},
    {"type": "Field", "fieldId": "Status", "read_only": false}
  ]
}

The inheritance rules are:

  • If a node has "read_only": true, it and all its descendants are read-only (unless overridden).

  • If a node has "read_only": false, it explicitly overrides any inherited read-only state.

  • If a node does not have a read_only property, it inherits from its parent.

  • Content nodes do not support read_only (they have no editable content).

In the layout editor preview, read-only fields are shown with a "Read-only" badge and a grey background.

Complex Example

This example combines multiple layout features including tabs, sections, horizontal layouts, and content:

{
  "type": "Tabs",
  "children": [
    {
      "type": "VerticalLayout",
      "label": "Overview",
      "children": [
        {
          "type": "Content",
          "html": "<h4>Basic Information</h4><p>Enter the core details for this item.</p>"
        },
        {
          "type": "HorizontalLayout",
          "children": [
            {"type": "Field", "fieldId": "Name", "columns": 8},
            {"type": "Field", "fieldId": "Status", "columns": 4}
          ]
        },
        {"type": "Field", "fieldId": "Description"}
      ]
    },
    {
      "type": "VerticalLayout",
      "label": "Details",
      "children": [
        {
          "type": "Section",
          "label": "Dates",
          "children": [
            {
              "type": "HorizontalLayout",
              "children": [
                {"type": "Field", "fieldId": "StartDate", "columns": 6},
                {"type": "Field", "fieldId": "EndDate", "columns": 6}
              ]
            }
          ]
        },
        {"type": "Content", "html": "<hr>"},
        {
          "type": "Section",
          "label": "Assignment",
          "children": [
            {"type": "Field", "fieldId": "AssignedTo"},
            {"type": "Field", "fieldId": "Priority"}
          ]
        }
      ]
    }
  ]
}

Validation Rules

The layout JSON is validated when saving:

  1. The root must be a valid node type (typically VerticalLayout, Section, or Tabs)

  2. All fieldId values must match active property definition names

  3. HorizontalLayout children must have columns values between 1 and 12

  4. HorizontalLayout total columns should not exceed 12

  5. Tabs children must have label properties

  6. read_only, if present, must be a boolean (true or false)

  7. Content nodes do not support read_only

Live Preview

The layout editor provides a live preview that updates as you type. This helps you visualize the layout structure before saving. Fields that exist in the layout are shown with their names and types. Any fields not included in your layout are listed in the "Fields not in layout" section - these will appear in an "Other Fields" area when viewing custom object instances.