Composition File

The {widgetName}.json widget definition file is a required resource in every widget bundle. It defines the UI composition—specifying which components render, their layout hierarchy, ordering, and how they dynamically bind to widget attributes.

This table lists the properties that you can specify in a {widgetName}.json file.

PropertyTypeRequired or OptionalDescription
typeStringRequiredThe content type identifier. Set this to lightning__agentforceWidget. This identifier applies to all supported Salesforce applications and platforms.
contentBodyObjectRequiredThe root content object containing the composition structure.
contentBody.widgetBodyObjectRequiredThe root component that holds the widget’s composition structure.

This example shows a composition file for a hotel card widget (hotelCard.json) that defines the visual structure and data binding tokens. The {!$attrs.attributeName} expressions reference widget attributes defined in the widget’s schema.json file.

1{
2  "type": "lightning__agentforceWidget",
3  "contentBody": {
4    "widgetBody": {
5      "definition": "tile/widget",
6      "children": [
7        {
8          "definition": "tile/card",
9          "attributes": {
10            "padding": "lg",
11            "variant": "default",
12            "maxWidth": "full"
13          },
14          "children": [
15            {
16              "definition": "tile/image",
17              "attributes": {
18                "src": "{!$attrs.imageUrl}",
19                "alt": "{!$attrs.title}"
20              }
21            },
22            {
23              "definition": "tile/text",
24              "attributes": {
25                "text": "{!$attrs.title}",
26                "variant": "h3",
27                "weight": "semibold"
28              }
29            },
30            {
31              "definition": "tile/text",
32              "attributes": {
33                "text": "{!$attrs.price}",
34                "variant": "body",
35                "weight": "medium"
36              }
37            },
38            {
39              "definition": "tile/text",
40              "attributes": {
41                "text": "{!$attrs.description}",
42                "variant": "body"
43              }
44            }
45          ]
46        }
47      ]
48    }
49  }
50}

Composition Building Blocks 

To build the visual structure shown in the code example, understand these fundamental layout elements:

  • Components: The atomic building units of a widget’s visual layout. Each component specifies a definition. Depending on the component and its rendering behavior, it can also specify attributes, children, and meta.
    • definition: The specific component to render (such as tile/card, tile/text, or title/image).
    • attributes: Configuration key-value pairs applied directly to the component. These pairs can be static values or dynamic token expressions.
    • children: An array of nested child components rendered sequentially inside the parent component container.
    • meta: Rendering instructions that control whether a component renders or repeats for items in a collection.
  • Root Component Requirement: Every widget structure requires a root widgetBody component with its definition set to "tile/widget". This configuration serves as the primary wrapper holding all subsequent child components.
  • Data Binding Expressions: Use the token syntax {!$attrs.attributeName} to reference widget attributes within component properties. The widget’s schema.json defines these attributes. Attributes receive their values at run time when you connect the widget to a Lightning type through attribute mapping.

Use Static Resources in Widgets 

Widget attributes can reference external static resources, such as image URLs. To render, the static resource must be accessible without authentication.

To enable loading static resources from a specific domain via MCP servers, add the domain as a Trusted URL in your org. After you set up the Trusted URL, Salesforce automatically provisions the Content Security Policy setting for the MCP server.

Use Salesforce Formulas in Widgets 

Widget composition supports a formula language based on the Salesforce formula engine. Use formulas to automatically generate live results based on computed values and conditional statements. You can use infix operators for math, comparison, and logic, and built-in functions for conditionals, string operations, and so on.

For example, the formula "text": "{!$order.subtotal * $order.taxRate}" computes the amount of tax on an order. See the HXL Playground for more examples of formulas.

Control Component Rendering with Meta Properties 

Use the meta object in a widget composition to control whether a component renders and to repeat a component for items in a collection.

The meta object supports these properties.

PropertyRequired or optionalDescription
ifOptionalReferences an expression that evaluates to a Boolean value. Includes the component only when the expression evaluates to true.

The if expression can reference a Boolean widget attribute, such as {!$attrs.isVerified}, or a Boolean property of the current item, such as {!$amenity.isAvailable}.
forEachOptionalReferences the collection whose items the component renders.
forItemOptionalDefines the variable used to reference the current item. The value must begin with $. If omitted, the value defaults to $Item.
forIndexOptionalDefines the variable used to reference the current item’s index. The value must begin with $.

Render a Component Conditionally 

Use meta.if to control whether a component and its children render. The expression must evaluate to a Boolean value. If the expression evaluates to true, the component and its children render. If it evaluates to false, the component and its children aren’t included in the rendered output.

A non-Boolean result, such as a number, string, or empty array, isn’t supported and causes an evaluation error. A missing or null-valued reference is treated as false.

This example renders a message only when the isVerified widget attribute evaluates to true.

1{
2  "definition": "tile/text",
3  "meta": {
4    "if": "{!$attrs.isVerified}"
5  },
6  "attributes": {
7    "text": "Verified hotel",
8    "variant": "body"
9  }
10}

In this example:

  • {!$attrs.isVerified} references the isVerified attribute defined in the widget’s schema.json file.
  • The tile/text component renders only when isVerified evaluates to true.

If the component contains children, excluding the component also excludes all its child components.

Use Complex Conditions 

Use supported comparison operators and expression functions to combine conditions.

1{
2  "definition": "tile/text",
3  "meta": {
4    "if": "{!AND($attrs.isAvailable, $attrs.price < 500)}"
5  },
6  "attributes": {
7    "text": "Available within budget",
8    "variant": "body"
9  }
10}

Render a Component for Each Collection Item 

Use meta.forEach to repeat a component for each item in a collection. Optionally, set meta.forItem to the variable that represents the current item. The forItem value must begin with $.If forItem is omitted, the current-item variable defaults to $Item.

This example renders a text component for each amenity in an amenities collection.

1{
2  "definition": "tile/text",
3  "meta": {
4    "forEach": "{!$attrs.amenities}",
5    "forItem": "$amenity"
6  },
7  "attributes": {
8    "text": "{!$amenity.name}",
9    "variant": "body"
10  }
11}

In this example:

  • {!$attrs.amenities} references the amenities collection supplied through the widget’s attribute contract.
  • $amenity represents the current item.
  • {!$amenity.name} references the name property of the current item.
  • The tile/text component renders once for each item in the collection.

This example omits meta.forItem, so the current-item variable defaults to $Item. The {!$Item.name} expression references the name property of the current item.

1{
2  "definition": "tile/text",
3  "meta": {
4    "forEach": "{!$attrs.amenities}"
5  },
6  "attributes": {
7    "text": "{!$Item.name}",
8    "variant": "body"
9  }
10}

The optional meta.forIndex property defines a variable that represents the current item’s index. The value must begin with $.

This example uses $amenityIndex to reference the current item’s index:

1{
2  "definition": "tile/text",
3  "meta": {
4    "forEach": "{!$attrs.amenities}",
5    "forItem": "$amenity",
6    "forIndex": "$amenityIndex"
7  },
8  "attributes": {
9    "text": "{!$amenity.name}",
10    "variant": "body"
11  }
12}

You can nest components that use meta.forEach to render multidimensional collections. Each iteration creates a separate scope for its item and index variables.

Combine Conditional Rendering and List Iteration 

When a component specifies both meta.forEach and meta.if, the condition is evaluated for each item in the collection. The component renders only for items whose condition evaluates to true.

This example renders only amenities whose isAvailable property evaluates to true.

1{
2  "definition": "tile/text",
3  "meta": {
4    "forEach": "{!$attrs.amenities}",
5    "forItem": "$amenity",
6    "if": "{!$amenity.isAvailable}"
7  },
8  "attributes": {
9    "text": "{!$amenity.name}",
10    "variant": "body"
11  }
12}

In this example:

  • meta.forEach iterates over the items in amenities.
  • $amenity represents the current item.
  • meta.if evaluates $amenity.isAvailable for the current item.
  • The component renders for the current item only when isAvailable evaluates to true.

Reference a Widget-Level Attribute in the Condition 

When the meta.if condition references a widget-level attribute (such as {!$attrs.showAmenities}) instead of the scoped forItem variable, the condition evaluates once for the entire collection. As a result, the whole list either renders or is hidden—rather than being evaluated per item.

This example renders the entire list of amenities only when the widget-level showAmenities attribute evaluates to true.

1{
2  "definition": "tile/text",
3  "meta": {
4    "forEach": "{!$attrs.amenities}",
5    "forItem": "$amenity",
6    "if": "{!$attrs.showAmenities}"
7  },
8  "attributes": {
9    "text": "{!$amenity.name}",
10    "variant": "body"
11  }
12}

In this example:

  • meta.if evaluates the widget-level {!$attrs.showAmenities} attribute, not a property of the current item.
  • Because the condition doesn’t reference the forItem variable ($amenity), it’s evaluated once for the whole collection.
  • If showAmenities evaluates to true, all amenities render. If it evaluates to false, none render.

The scope of the meta.if condition determines the rendering behavior. When the condition references the forItem variable (such as $amenity.isAvailable), it’s evaluated per item. When it references a widget-level attribute (such as $attrs.showAmenities), it’s evaluated once for the entire collection.

Note

See Also

Beta Feature

Headless Experience Layer is a pilot or beta service that is subject to the Beta Services Terms at Ageements - Salesforce.com or a written Unified Pilot Agreement if executed by Customer, and applicable terms in the Product Terms Directory. Use of this pilot or beta service is at the Customer's sole discretion.