thumbnail

Demystifying the Salesforce Opportunity Record Page: A Deep Dive into FlexiPage Structure for Dynamic Forms

Marc Swan Marc Swan | 7 min read
4 months ago

Have you ever wondered what makes your Opportunity record page tick after you enable Dynamic Forms? Today, we’re going to pull back the curtain and take a peek at the inner workings of a FlexiPage Record Page. Buckle up, because we’re about to get up close and personal with some JSON metadata!

The Big Picture

First things first: what exactly is a FlexiPage Record Page? In essence, it’s the blueprint that tells Salesforce how to display all that juicy Opportunity data. It’s like the architectural plans for a house, but instead of rooms and windows, we’re dealing with fields and components.

The whole shebang is wrapped up in a JSON structure that might look intimidating at first glance, but don’t worry — we’ll break it down piece by piece.

The Anatomy of our Opportunity Page

Let’s start with the skeleton of our page. Remember that Lightning Record Pages have several pre-defined layouts or formats. For us — it’s divided into a few key regions:

  1. Header: This is where you’ll find the highlights panel — you know, that handy summary at the top of the page.
  2. Main Content: The meat and potatoes of our page, typically organized into tabs and/or accordions.
  3. Sidebar: Often home to related lists and other supplementary info.

FlexiPage Formats

Diving into the Details Tab

Now, let’s zoom in on the Details tab — this is where the real action happens. It’s structured like a Russian nesting doll, with layers upon layers of organization. This example is what it looks like when you convert an Out-of-the-box Opportunity record page to Dynamic Forms.

Building a Dynamic Form

The Accordion

At the top level, we’ve got an accordion component. It’s not for making music (though that would be cool), but for organizing our fields into collapsible sections. In our example, we’ve got two main sections:

1. Opportunity Information
2. Additional Fields

Opportunity Information: The Star of the Show

This section is prime real estate — it’s where you’ll find the most crucial Opportunity data. It’s split into two columns to make the most of the available space:

Column 1:
- Owner (read-only, because we don’t want any accidental ownership changes!)
- Is Private (for those hush-hush deals)
- Name (required, because every opportunity needs a name)
- Account
- Type
- Lead Source
- Sub Stage

Column 2:
- Amount (show me the money!)
- Expected Revenue (read-only, let Salesforce do the math)
- Close Date (required, we need to know when to pop the champagne)
- Next Step
- Stage (required, because every journey has stages)
- Probability
- Campaign

First, let’s look at the JSON for the two columns:

{
  "appendable": null,
  "itemInstances": [
    {
      "componentInstance": null,
      "fieldInstance": {
        "fieldInstanceProperties": [
          {
            "name": "uiBehavior",
            "value": "readonly"
          }
        ],
        "fieldItem": "Record.OwnerId",
        "identifier": "RecordOwnerIdField",
        "visibilityRule": null
      }
    },
    {
      "componentInstance": null,
      "fieldInstance": {
        "fieldInstanceProperties": [
          {
            "name": "uiBehavior",
            "value": "none"
          }
        ],
        "fieldItem": "Record.IsPrivate",
        "identifier": "RecordIsPrivateField",
        "visibilityRule": null
      }
    },
    // ... other fields for Column 1
  ],
  "mode": null,
  "name": "Facet-0ab55fc9-0cbd-4425-84d0-a90d8b25edf8",
  "prependable": null,
  "replaceable": null,
  "type": "Facet"
},
{
  "appendable": null,
  "itemInstances": [
    {
      "componentInstance": null,
      "fieldInstance": {
        "fieldInstanceProperties": [
          {
            "name": "uiBehavior",
            "value": "none"
          }
        ],
        "fieldItem": "Record.Amount",
        "identifier": "RecordAmountField",
        "visibilityRule": null
      }
    },
    {
      "componentInstance": null,
      "fieldInstance": {
        "fieldInstanceProperties": [
          {
            "name": "uiBehavior",
            "value": "readonly"
          }
        ],
        "fieldItem": "Record.ExpectedRevenue",
        "identifier": "RecordExpectedRevenueField",
        "visibilityRule": null
      }
    },
    // ... other fields for Column 2
  ],
  "mode": null,
  "name": "Facet-b10a35b7-1c9d-46eb-af65-abda91eeb95d",
  "prependable": null,
  "replaceable": null,
  "type": "Facet"
}

Now, let’s explain the Facet mapping:

  1. Column Facets:
  • Column 1 is represented by the Facet named Facet-0ab55fc9–0cbd-4425–84d0-a90d8b25edf8
  • Column 2 is represented by the Facet named Facet-b10a35b7–1c9d-46eb-af65-abda91eeb95d

2. Section Facet: These two column Facets are then grouped into a section Facet. Here’s the JSON for that:

{
  "appendable": null,
  "itemInstances": [
    {
      "componentInstance": {
        "componentInstanceProperties": [
          {
            "name": "columns",
            "type": null,
            "value": "Facet-8e8f7efa-8283-4068-95f2-e2a535ac3945",
            "valueList": null
          },
          {
            "name": "label",
            "type": null,
            "value": "@@@SFDCOpportunity_InformationSFDC@@@",
            "valueList": null
          }
        ],
        "componentName": "flexipage:fieldSection",
        "componentType": null,
        "flexipageDataSources": null,
        "identifier": "flexipage_fieldSection",
        "visibilityRule": null
      },
      "fieldInstance": null
    }
  ],
  "mode": null,
  "name": "Facet-5bdea8d8-fee0-4c64-a430-6b4311a65979",
  "prependable": null,
  "replaceable": null,
  "type": "Facet"
}

3. Facet Mapping Explanation:

  • The two column Facets (Facet-0ab55fc9–0cbd-4425–84d0-a90d8b25edf8 and Facet-b10a35b7–1c9d-46eb-af65-abda91eeb95d) are combined into another Facet (Facet-8e8f7efa-8283–4068–95f2-e2a535ac3945), which represents the entire two-column layout.
  • This combined Facet is then used in the “columns” property of the flexipage:fieldSection component.
  • The flexipage:fieldSection component is wrapped in another Facet (Facet-5bdea8d8-fee0–4c64-a430–6b4311a65979), which represents the entire “Opportunity Information” section.

4. Section Title:

  • The section title is defined in the “label” property of the flexipage:fieldSection component.
  • The value “@@@SFDCOpportunity_InformationSFDC@@@” is a dynamic value that will be replaced with the actual label “Opportunity Information” when rendered.

This nested structure of Facets allows for a flexible and organized layout:

  • Individual fields are grouped into column Facets.
  • Column Facets are combined into a layout Facet.
  • The layout Facet is used in a fieldSection component.
  • The fieldSection component is wrapped in another Facet, which represents the entire section.

This structure makes it easy to reorganize the layout by simply changing the Facet references, without having to move individual fields around in the JSON. It also allows for easy addition or removal of fields within each column, and even adding or removing entire columns if needed.

Additional Fields: The Supporting Cast

This section is further divided into four subsections, each playing a supporting role in our Opportunity story:

1. Other Information: This section is actually empty in our example. Maybe it’s shy?

2. Additional Information:
— Column 1: Order Number, Current Generators, Tracking Number
— Column 2: Main Competitors, Delivery/Installation Status

3. System Information:
— Column 1: Created By (read-only, for obvious reasons)
— Column 2: Last Modified By (also read-only, we’re not rewriting history here)

4. Description Information:
— A single column with Description and Source fields

Completed Record Dynamic Form

Why This Structure Matters

You might be thinking, “That’s a lot of nested components!” And you’d be right. But there’s method to this madness. This structure allows for:

  1. Flexibility: Need to add a new field? Just pop it into the appropriate section.
  2. Organization: Related fields are grouped together, making it easier for users to find what they need.
  3. Space Efficiency: By using columns, we can display more information without making the page excessively long.

There’s another key reason this all matter, but that’s content for a later article.

Customization is Key

Adding a field to a Dynamic Form
Image From Salesforce Documentation

The beauty of this structure is its customizability. Don’t like how something is laid out? With a few clicks in the Lightning App Builder, you can rearrange fields, add new components, or even create entirely new sections.

Wrapping Up

Next time you’re looking at an Opportunity in Salesforce, you’ll know there’s a whole world of JSON and metadata working behind the scenes to bring that information to your screen.

Remember, understanding this structure isn’t just for the techie folks. Whether you’re an admin, developer, or power user, knowing how your pages are built can help you optimize your Salesforce org and create a better experience for your users. This becomes increasingly important if you need to process Dynamic Form enabled pages using LWC (Lightning Web Components) or Aura components to generate even more unique and custom layouts — which I will explain in more detail in a later post.

So go forth and flex those FlexiPage muscles! Your Opportunities (and your users) will thank you.

Discussions

Login to Post Comments
No Comments Posted