Build Rich UI Experiences with HXL Widgets
Widgets are platform-independent UI compositions. With widgets, you define rich, interactive interfaces once and deploy them across supported Salesforce applications and third-party platforms.
You build widgets by defining their composition in JSON files. Understand these core concepts to compose and deploy widgets.
Supported Applications and Platforms
Widgets can be deployed to:
- Agentforce Employee agent in Lightning Experience
- ChatGPT (via Model Context Protocol)
- Claude (via Model Context Protocol)
- Slackbot (via Model Context Protocol)
Building Blocks of a Widget
A widget consists of these building blocks.
- Composition file defines the visual UI composition. It specifies which components render, their hierarchical nesting, ordering, and data bindings by using
{!$attrs.attributeName}token expressions. - Widget configuration file defines the widget’s label, description, and type.
- Schema file defines the attribute contract. It outlines the attributes and their associated Lightning types that the widget accepts, including validation rules, data types, and display metadata.
UiWidgetBundle Metadata Type
The UiWidgetBundle metadata type describes the widgets. It’s available in API version 67.0 and later.
Understand the UiWidgetBundle Structure
UiWidgetBundle components are stored in the uiWidgets folder and consist of a composition file, widget configuration file, and optional schema file. See UiWidgetBundle.
For a detailed example of this structure, see Example: Mapping a Hotel Card Widget.
Use Salesforce CLI or Metadata API to Deploy UiWidgetBundles
To deploy a UiWidgetBundle to your Salesforce org, use Metadata API or Salesforce CLI commands. Metadata API uses a manifest file that defines the metadata that you want to deploy.
Here’s an example package.xml manifest file for a UiWidgetBundle that includes the widget hotelCard.
1<?xml version="1.0" encoding="UTF-8"?>
2<Package xmlns="http://soap.sforce.com/2006/04/metadata">
3 <types>
4 <members>hotelCard</members>
5 <name>UiWidgetBundle</name>
6 </types>
7 <version>67.0</version>
8</Package>To delete a widget, you must deploy a destructiveChanges package to your org that lists the widgets to delete.
See Also
- Metadata API Developer Guide: Deploying and Retrieving Metadata with the Zip File
- Metadata API Developer Guide: Deleting Components from an Organization
Salesforce CLI Commands
Use the Salesforce CLI project commands to deploy, retrieve, and track the source files for the UiWidgetBundle metadata type in your Salesforce DX project. See project Commands in the Salesforce CLI Command Reference.
This example shows how to deploy a UiWidgetBundle called hotelCard to an org with alias my-org:
1sf project deploy start --metadata UiWidgetBundle:hotelCard --target-org my-orgConnect Your Widget to a Custom Lightning Type
To render dynamic data in a widget, connect the widget to a custom Lightning type. In the custom Lightning type’s renderer.json file, reference the widget and map properties defined by the custom Lightning type to attributes defined in the widget’s schema.json file.
The widget bundle’s composition file, widget configuration file, and schema file don’t change based on the supported Salesforce application or third-party platform where the widget renders.
Don’t use the Lightning Types page in Setup to create or modify custom Lightning types that reference widgets. Define and update these custom Lightning types in your Salesforce DX project, and deploy the LightningTypeBundle metadata by using Salesforce CLI or Metadata API.
Note
Choose the Custom Lightning Type Configuration
Choose the custom Lightning type configuration based on the scenario in which the widget renders.
| Rendering Scenario | Custom Lightning Type Configuration | Widget Attribute Mapping |
|---|---|---|
| Agentforce action output rendered in Lightning Experience | One Apex-based custom Lightning type | Direct mapping |
| MCP server tool output rendered in an MCP channel | Two object-based custom Lightning types, one in the MCP result wrapper role and one in the MCP payload role | Nested mapping through outputValues |
For Agentforce action output, the Apex-based custom Lightning type references the Apex class that defines the structured output’s schema. The custom Lightning type’s renderer.json file maps properties from that schema directly to attributes defined in the widget’s schema.json file.
For MCP server tool output from invocable actions, primarily Apex invocable actions exposed as MCP tools, create two object-based custom Lightning types. This configuration currently applies only to invocable actions exposed as MCP tools. Follow this fixed structure:
- The MCP result wrapper custom Lightning type represents the complete result returned by the MCP server tool, including
actionName,isSuccess, andoutputValues. - The MCP payload custom Lightning type defines the structure referenced by the MCP result wrapper custom Lightning type’s
outputValuesproperty.
The terms MCP result wrapper custom Lightning type and MCP payload custom Lightning type describe roles in this configuration. They aren’t categories of custom Lightning types. Both are object-based custom Lightning types.
The outputValues property in the MCP result wrapper custom Lightning type references the MCP payload custom Lightning type. The MCP result wrapper custom Lightning type’s renderer.json file maps properties under outputValues to widget attributes.
For general information about creating custom Lightning types, see Apex-Based Custom Lightning Types and Object-Based Custom Lightning Types.
Reference the Widget
Reference your widget in the Lightning type’s renderer.json file by using the componentOverrides syntax. The definition field uses this format: @widget/{namespace}/{widgetName}
- Local Org (
@widget/c/hotelCard): References a widget namedhotelCardin your org’s namespace.
This example shows a basic widget reference:
1{
2 "renderer": {
3 "componentOverrides": {
4 "$": {
5 "definition": "@widget/c/hotelCard"
6 }
7 }
8 }
9}For Agentforce action output, add renderer.json to the Apex-based custom Lightning type.
For MCP server tool output, add renderer.json to the MCP result wrapper custom Lightning type.
For widget references, create a renderer.json file at the root level (parallel to schema.json) in the Lightning type folder, without channel-specific subfolders.
Referencing widgets in editor.json isn’t currently supported. When you reference a widget in a Lightning type, create a renderer.json file at the root level (parallel to schema.json). Don’t use channel-specific subfolders. This structure differs from Lightning Web Component (LWC) overrides, which use channel-specific subfolders (such as lightningDesktopGenAi/). See Lightning Type Structure for Widgets (Beta).
Note
Widget Attribute Mapping
Attribute mapping connects the data properties represented by a custom Lightning type to attributes defined in the widget’s schema.json file. Define the mapping in the attributes object of the custom Lightning type’s renderer.json file.
In the renderer’s attributes object, each entry maps a custom Lightning type property to a widget attribute.
- The key is an attribute defined in the widget’s
schema.jsonfile. - The value references a property or nested property represented by the custom Lightning type. Use an expression such as
{!$attrs.propertyName}for a direct property or{!$attrs.parentProperty.propertyName}for a nested property.
Attribute mapping requires a schema.json file in your widget to define the attributes. Widgets without a schema.json file can only display static content.
Note
The property reference depends on the rendering scenario:
- Agentforce action output uses direct property references.
- MCP server tool output uses nested property references through
outputValues.
Map Agentforce Action Output
For Agentforce action output rendered in Lightning Experience, map properties represented by the Apex-based custom Lightning type directly to widget attributes.
This example shows attribute mapping in a renderer.json file that connects properties represented by the custom Lightning type to the hotelCard widget.
1{
2 "renderer": {
3 "componentOverrides": {
4 "$": {
5 "definition": "@widget/c/hotelCard",
6 "attributes": {
7 "hotelId": "{!$attrs.hotelId}",
8 "name": "{!$attrs.name}",
9 "city": "{!$attrs.city}",
10 "checkInTime": "{!$attrs.checkInTime}",
11 "checkOutTime": "{!$attrs.checkOutTime}",
12 "pricePerNight": "{!$attrs.pricePerNight}",
13 "rating": "{!$attrs.rating}"
14 }
15 }
16 }
17 }
18}In this example:
- The keys (
hotelId,name,city,checkInTime,checkOutTime,pricePerNight, andrating) are attributes defined in the widget’sschema.jsonfile. - The values (
{!$attrs.hotelId},{!$attrs.name},{!$attrs.city},{!$attrs.checkInTime},{!$attrs.checkOutTime},{!$attrs.pricePerNight}, and{!$attrs.rating}) directly reference properties represented by the Apex-based custom Lightning type.
For information about creating the custom Lightning type, see Apex-Based Custom Lightning Types.
Map MCP Server Tool Output
For a custom MCP server tool rendered in ChatGPT, Claude, or Slackbot, the MCP result wrapper custom Lightning type defines the outputValues property. The lightning:type value of outputValues references the MCP payload custom Lightning type.
In the MCP result wrapper custom Lightning type’s renderer.json file, use nested property references through outputValues to map MCP server tool output to widget attributes.
This example maps hotel information represented by an MCP result wrapper custom Lightning type to the hotelCard widget.
1{
2 "renderer": {
3 "componentOverrides": {
4 "$": {
5 "definition": "@widget/c/hotelCard",
6 "attributes": {
7 "hotelId": "{!$attrs.outputValues.hotelInfo.hotelId}",
8 "name": "{!$attrs.outputValues.hotelInfo.name}",
9 "city": "{!$attrs.outputValues.hotelInfo.city}",
10 "checkInTime": "{!$attrs.outputValues.hotelInfo.checkInTime}",
11 "checkOutTime": "{!$attrs.outputValues.hotelInfo.checkOutTime}",
12 "pricePerNight": "{!$attrs.outputValues.hotelInfo.pricePerNight}",
13 "rating": "{!$attrs.outputValues.hotelInfo.rating}"
14 }
15 }
16 }
17 }
18}In this example:
- The keys (
hotelId,name,city,checkInTime,checkOutTime,pricePerNight, andrating) are attributes defined in the widget’sschema.jsonfile. $attrs.outputValuesreferences theoutputValuesproperty in the MCP result wrapper custom Lightning type. Thelightning:typevalue of this property references the MCP payload custom Lightning type.hotelInfois a property defined in the MCP payload custom Lightning type. Itslightning:typevalue references theHotelSearchResult.HotelApex class.- The final segment of each property reference, such as
hotelId,name, orrating, references a field in theHotelSearchResult.HotelApex class.
The widget schema remains a flat attribute contract. Don’t reproduce the outputValues structure in the widget’s schema.json file. Only the MCP result wrapper custom Lightning type’s renderer.json file references the nested MCP server tool result structure.
For the required custom Lightning type configuration and MCP-specific schema requirements, see Configure Custom Lightning Types for an MCP Server Tool.
See Also
- Get Started with Lightning Types
- Example: Mapping a Hotel Card Widget for Agentforce
- Example: Mapping a Hotel Card Widget for MCP
Configure Custom Lightning Types for an MCP Server Tool
To render MCP server tool output in a widget, create two object-based custom Lightning types: an MCP result wrapper custom Lightning type and an MCP payload custom Lightning type. These terms describe the roles of the custom Lightning types in this configuration, not categories of custom Lightning types.
For general information about object-based custom Lightning types, see Object-Based Custom Lightning Types.
Understand the Custom Lightning Type Roles
A custom MCP server tool returns a result containing actionName, isSuccess, and outputValues. At runtime, the outputValues property contains the action-specific payload.
Because a custom Lightning type can’t reference itself, use a separate MCP payload custom Lightning type to define the structure of the payload. The lightning:type value of outputValues references this custom Lightning type.
The MCP result wrapper custom Lightning type represents the complete MCP server tool result. Its outputValues property references the MCP payload custom Lightning type.
Define the MCP Payload Custom Lightning Type
The lightning:type value of the MCP result wrapper custom Lightning type’s outputValues property references the MCP payload custom Lightning type. The MCP payload custom Lightning type defines the structure of the action-specific payload. Its properties can use Apex class type references to describe values returned by the Apex invocable action.
This example defines a hotelInfo property whose lightning:type value references the Hotel inner class in the HotelSearchResult Apex class.
1{
2 "title": "Hotel Info Output Values",
3 "description": "Payload fields from the HotelSearchResult response",
4 "type": "object",
5 "lightning:type": "lightning__objectType",
6 "lightning:tags": ["mcp"],
7 "unevaluatedProperties": false,
8 "properties": {
9 "hotelInfo": {
10 "title": "Hotel Info",
11 "lightning:type": "@apexClassType/c__HotelSearchResult$Hotel"
12 }
13 }
14}For an MCP payload custom Lightning type:
- Set type to
object. - Set
lightning:typetolightning__objectType. - Include
mcpinlightning:tags. - Set
unevaluatedPropertiestofalse. - Define the properties in the payload.
In this example, the lightning:type value of hotelInfo references the Hotel inner class in the HotelSearchResult Apex class.
Define the MCP Result Wrapper Custom Lightning Type
The MCP result wrapper custom Lightning type represents the complete result returned by the MCP server tool.
Define these properties:
actionName: The name of the invoked action.isSuccess: Indicates whether the action completed successfully.outputValues: The action-specific payload. Itslightning:typevalue references the MCP payload custom Lightning type.
1{
2 "title": "Hotel Info Result",
3 "description": "Invocable-action result envelope for the HotelSearchResult MCP tool",
4 "type": "object",
5 "lightning:type": "lightning__objectType",
6 "lightning:tags": ["mcp"],
7 "unevaluatedProperties": false,
8 "properties": {
9 "actionName": { "title": "Action Name", "lightning:type": "lightning__textType" },
10 "isSuccess": { "title": "Is Success", "lightning:type": "lightning__booleanType" },
11 "outputValues": { "title": "Output Values", "lightning:type": "c__hotelInfoOutputValues" }
12 }
13}In this example, the lightning:type value of outputValues references hotelInfoOutputValues, the MCP payload custom Lightning type.
Add the Renderer
Add renderer.json to the root of the MCP result wrapper custom Lightning type bundle, parallel to its schema.json file.
Map nested properties under outputValues to the flat attributes defined in the widget’s schema.json file.
This example maps hotel information under outputValues.hotelInfo to attributes defined in the hotelCard widget’s schema.
1{
2 "renderer": {
3 "componentOverrides": {
4 "$": {
5 "definition": "@widget/c/hotelCard",
6 "attributes": {
7 "hotelId": "{!$attrs.outputValues.hotelInfo.hotelId}",
8 "name": "{!$attrs.outputValues.hotelInfo.name}",
9 "city": "{!$attrs.outputValues.hotelInfo.city}",
10 "checkInTime": "{!$attrs.outputValues.hotelInfo.checkInTime}",
11 "checkOutTime": "{!$attrs.outputValues.hotelInfo.checkOutTime}",
12 "pricePerNight": "{!$attrs.outputValues.hotelInfo.pricePerNight}",
13 "rating": "{!$attrs.outputValues.hotelInfo.rating}"
14 }
15 }
16 }
17 }
18}In this example:
- The keys (
hotelId,name,city,checkInTime,checkOutTime,pricePerNight, andrating) are attributes defined in thehotelCardwidget’sschema.jsonfile. outputValuesis a property in the MCP result wrapper custom Lightning type.hotelInfois a property in the MCP payload custom Lightning type.- The final segment of each expression references a property in the
HotelSearchResult.HotelApex class.
Don’t add renderer.json to the MCP payload custom Lightning type. The renderer applies to the complete MCP server tool result represented by the MCP result wrapper custom Lightning type.
Understand the File Structure
This example uses an MCP server tool for hotel information and a widget named hotelCard.
1myProject/
2 force-app/
3 main/
4 default/
5 uiWidgets/
6 hotelCard/
7 hotelCard.json
8 hotelCard.uiwidget-meta.xml
9 schema.json
10 lightningTypes/
11 hotelInfoResult/
12 schema.json
13 renderer.json
14 hotelInfoOutputValues/
15 schema.jsonIn this structure:
hotelInfoOutputValuesis the bundle for the MCP payload custom Lightning type.hotelInfoResultis the bundle for the MCP result wrapper custom Lightning type.- The
hotelInfoResultbundle containsrenderer.json. hotelCardis the widget bundle.
See Also
Understand Namespace Prefixes for Widget References
When you reference a widget from a Lightning type, use the correct namespace prefix.
For widgets created in your org
Use the c namespace prefix. This rule applies even if your org has its own namespace. For example, if your org’s namespace is myOrgNamespace and you create a widget named hotelCard, refer to it as c/hotelCard.
This renderer.json file uses the c namespace to reference a widget.
1{
2 "renderer": {
3 "componentOverrides": {
4 "$": {
5 "definition": "@widget/c/hotelCard"
6 }
7 }
8 }
9}See Also
Beta Feature