# developer Headless Experience Layer Developer Guide (Beta) (headless-experience-layer) - Full Documentation
# Accordion
**`tile/accordion`**
Organizes content into vertically stacked, expandable sections. Each section has a header and nested content.
## Properties
This component has no configurable properties. Provide content through child components.
## Usage
Use an accordion to organize content into vertically stacked, expandable sections to reduce visual clutter on dense screens. An accordion has no attributes of its own. To provide content in an accordion, use [`tile/accordionItem`](https://developer.salesforce.com/docs/platform/hxl/references/hxl-reference-about/accordionItem.md) child components.
```json
{
"definition": "tile/accordion",
"children": [
{
"definition": "tile/accordionItem",
"attributes": { "title": "What is your refund policy?" },
"children": [
{
"definition": "tile/text",
"attributes": {
"text": "We offer a 30-day money-back guarantee on all purchases."
}
}
]
},
{
"definition": "tile/accordionItem",
"attributes": { "title": "How long does shipping take?" },
"children": [
{
"definition": "tile/text",
"attributes": {
"text": "Standard shipping typically takes 5-7 business days."
}
}
]
}
]
}
```
To draw attention to the first section, open it by default with `isExpanded` and add an `iconName` for a visual cue in the header.
```json
{
"definition": "tile/accordion",
"children": [
{
"definition": "tile/accordionItem",
"attributes": { "title": "Getting Started", "isExpanded": true, "iconName": "star" },
"children": [
{
"definition": "tile/text",
"attributes": { "text": "Follow the steps below to get started." }
}
]
},
{
"definition": "tile/accordionItem",
"attributes": { "title": "Advanced Topics", "iconName": "settings" },
"children": [
{
"definition": "tile/text",
"attributes": { "text": "Explore more complex features and customizations." }
}
]
}
]
}
```
For richer sections, wrap multiple pieces in a `tile/column` to stack them, and mix in `tile/badge` or `tile/button`.
```json
{
"definition": "tile/accordionItem",
"attributes": { "title": "Product Features", "iconName": "heart" },
"children": [
{
"definition": "tile/column",
"attributes": { "gap": "sm" },
"children": [
{
"definition": "tile/text",
"attributes": { "text": "High-quality materials" }
},
{
"definition": "tile/badge",
"attributes": { "label": "New", "variant": "info" }
}
]
}
]
}
```
## Design Guidelines
Consider these guidelines when working with accordions.
- Keep section titles concise and descriptive so users can scan headers to find what they need.
- To surface the most important section immediately, set `isExpanded` on one item rather than leaving every section collapsed.
- Sections expand and collapse independently, so more than one can be open at once. Use per-item `isExpanded` to seed which sections start open.
- When content should always be visible or is short enough not to warrant collapsing, use a `tile/column` instead of hiding it behind an accordion.
## Limitations
Note any limitations that apply to this component.
### Slackbot
No known limitations for `tile/accordion` in Slackbot.
### ChatGPT
No known limitations for `tile/accordion` in ChatGPT.
### Agentforce
No known limitations for `tile/accordion` in Agentforce.
## See Also
- [HXL Lightning Types Reference](https://developer.salesforce.com/docs/platform/hxl/references/hxl-lightning-types.md)
- [_HXL Playground_: Accordion](https://www.headlessexperiencelayer.com/#components/accordion)
# Accordion Item
**`tile/accordionItem`**
Creates an expandable section within an accordion. Each section has a clickable header with a title and optional icon.
## Properties
| Name | Required | Lightning Type | Default | Description |
| ---- | -------- | -------------- | ------- | ----------- |
| iconAlt | No | `lightning__textType` | | Alternative text describing what the header icon conveys. When omitted or empty, the icon is treated as decorative and hidden from assistive technologies. |
| iconName | No | `lightning__iconName` | | An icon identifier shown in the section header next to the title. |
| isExpanded | No | `lightning__booleanType` | false | Specifies whether this section is currently expanded to show its content. |
| subtitle | No | `lightning__textType` | | Secondary text shown beneath the title in the accordion section header. |
| title | Yes | `lightning__textType` | | The header text for the clickable trigger on the accordion section. |
## Usage
Use an accordion item to define a section within a `tile/accordion`. Each item renders a clickable header with its `title`, optional `subtitle`, and optional `iconName`, and reveals its child content when expanded. Accordion items are only valid as direct children of a [`tile/accordion`](https://developer.salesforce.com/docs/platform/hxl/references/hxl-reference-about/accordion.md).
```json
{
"definition": "tile/accordion",
"children": [
{
"definition": "tile/accordionItem",
"attributes": { "title": "Shipping Details", "iconName": "settings" },
"children": [
{
"definition": "tile/text",
"attributes": { "text": "Standard shipping takes 5-7 business days." }
}
]
}
]
}
```
Add a `subtitle` to show secondary text under the title, useful for a short preview of the section's content.
```json
{
"definition": "tile/accordionItem",
"attributes": { "title": "Shipping Details", "subtitle": "Rates, timelines, and tracking" },
"children": [
{
"definition": "tile/text",
"attributes": { "text": "Standard shipping takes 5-7 business days." }
}
]
}
```
To draw a section open on first render, set `isExpanded` to `true`.
```json
{
"definition": "tile/accordionItem",
"attributes": { "title": "Getting Started", "isExpanded": true },
"children": [
{
"definition": "tile/text",
"attributes": { "text": "Follow the steps below to get started." }
}
]
}
```
To stack multiple pieces of content in one section, wrap them in a `tile/column`, and mix in components like `tile/badge` or `tile/button` for richer sections.
```json
{
"definition": "tile/accordionItem",
"attributes": { "title": "Beginner Level", "iconName": "star" },
"children": [
{
"definition": "tile/column",
"attributes": { "gap": "sm" },
"children": [
{
"definition": "tile/text",
"attributes": { "text": "Introduction to basic concepts." }
},
{
"definition": "tile/badge",
"attributes": { "label": "5 lessons", "variant": "info" }
}
]
}
]
}
```
## Design Guidelines
Consider these guidelines when working with accordion items.
- Keep each `title` concise and descriptive so users can scan headers and find the right section quickly.
- Use `subtitle` for a short, scannable preview of a section's content so users can decide whether to expand it without guessing from the title alone.
- To highlight the most important section, set `isExpanded` on it rather than leaving every section collapsed.
- Do not depend on whether opening one section collapses the others — each surface decides that expansion behavior, so use `isExpanded` only to seed the initial state.
- Add an `iconName` when a visual cue helps users recognize the section immediately, but omit it when titles are already clear.
## Limitations
Note any limitations that apply to this component.
### Slackbot
No known limitations for `tile/accordionItem` in Slackbot.
### ChatGPT
No known limitations for `tile/accordionItem` in ChatGPT.
### Agentforce
No known limitations for `tile/accordionItem` in Agentforce.
## See Also
- [HXL Lightning Types Reference](https://developer.salesforce.com/docs/platform/hxl/references/hxl-lightning-types.md)
- [_HXL Playground_: Accordion Item](https://www.headlessexperiencelayer.com/#components/accordionItem)
# Avatar
**`tile/avatar`**
Identifies a user, entity, or object visually. An avatar contains the image URL, text initials, icon name, alternative text, shape, and size.
## Properties
| Name | Required | Lightning Type | Default | Description |
| ---- | -------- | -------------- | ------- | ----------- |
| alt | No | `lightning__textType` | | An alternative text that identifies the entity. Maximum 125 characters, HTML-encoded. |
| iconName | No | `lightning__iconName` | | A semantic icon identifier representing the entity, appearing when image URL and initials are absent. For example: `user`, `users`, `building`. |
| initials | No | `lightning__textType` | | An abbreviation string up to 2 characters. Use Unicode characters up to a maximum of 3 characters. For example: `JD` for `John Doe`, `AM` for `Amazon`, `+5` for groups. |
| shape | No | `lightning__textType` | `circle` | The shape that indicates the entity category. Valid values include `circle` for people, `square` for objects or organizations, or `rounded` for hybrid entities. |
| size | No | `lightning__textType` | `md` | The size of the avatar. Valid values include `xs` for extra small, `sm` for small, `md` for medium (default), `lg` for large, or `xl` for extra large. |
| src | No | `lightning__urlType` | | The absolute or relative image URL, URL-encoded, referencing a JPEG, PNG, WebP, SVG, or GIF file. |
## Usage
Use an avatar to display a visual identifier for a person, organization, or entity. Provide at least one of `src`, `initials`, or `iconName`. The avatar prioritizes the `src` value. If `src` and `iconName` are missing, the `initials` value is shown.
Use `shape` to signal entity category: `"circle"` (default) for people, `"square"` for organizations or objects, `"rounded"` for hybrid entities such as AI assistants or teams.
```json
{
"definition": "tile/avatar",
"attributes": {
"src": "https://www.example.com/photo.jpg",
"alt": "Sarah Johnson"
}
}
```
When no image is available, use `initials` to provide a visible fallback.
```json
{
"definition": "tile/avatar",
"attributes": {
"initials": "SJ",
"alt": "Sarah Johnson"
}
}
```
To build a user identity header that places an avatar next to a name, combine `tile/avatar` with `tile/text` inside a `tile/row`.
```json
{
"definition": "tile/row",
"attributes": { "align": "center", "gap": "sm" },
"children": [
{
"definition": "tile/avatar",
"attributes": {
"initials": "SJ",
"alt": "Sarah Johnson"
}
},
{
"definition": "tile/text",
"attributes": { "text": "Sarah Johnson" }
}
]
}
```
**note:** `tile/avatar` has the same image source and format restrictions as `tile/image`.
Additionally, the `src` attribute must reference a resource that's accessible without authentication. To enable access to the resource, add the domain as a trusted URL. For more information, see [Use Static Resources in Widgets](https://developer.salesforce.com/docs/platform/hxl/guide/hxl-widget-composition.html#use-static-resources-in-widgets).
## Size
Use these `size` values to control the avatar's dimensions.
- `xs`: Extra small avatars for dense lists or inline mentions alongside text.
- `sm`: Small avatars for compact rows and secondary contexts.
- `md` (default): Medium avatars for most standalone and labeled uses.
- `lg`: Large avatars for profile headers and prominent identity displays.
- `xl`: Extra large avatars for a hero or focal identity such as a profile page.
## Design Guidelines
Consider these guidelines when working with avatars.
- Omit `shape` for people to use the default circle; set `shape: "square"` for organizations or objects, and `shape: "rounded"` for AI assistants or teams.
- Provide a meaningful `alt` value such as a user's first and last name. Use an empty string only for decorative avatars.
- Provide `initials` alongside `src` as a text fallback for when the image fails to load.
- Use `iconName: "users"` for groups and `iconName: "building"` for organizations when neither an image nor initials are available.
## Limitations
Note any limitations that apply to this component.
### Slackbot
No known limitations for `tile/avatar` in Slackbot.
### ChatGPT
No known limitations for `tile/avatar` in ChatGPT.
### Agentforce
`size: xl` falls back to `large`. `shape: rounded` falls back to `square` with custom CSS.
## See Also
- [HXL Lightning Types Reference](https://developer.salesforce.com/docs/platform/hxl/references/hxl-lightning-types.md)
- [_HXL Playground_: Avatar](https://www.headlessexperiencelayer.com/#components/avatar)
# Badge
**`tile/badge`**
Presents a small inline indicator for categorization or status.
## Properties
| Name | Required | Lightning Type | Default | Description |
| ---- | -------- | -------------- | ------- | ----------- |
| label | Yes | `lightning__textType` | | Short text content for the badge. |
| variant | No | `lightning__textType` | `secondary` | Visual style and status classification. |
## Usage
Use a badge to display a short inline label for categorization or status. For semantic states such as a record's health or pipeline stage, use a status variant such as `success`, `warning`, `error`, or `info`.
**note:** Avoid using a badge for interactive elements. To create a clickable label, use [`tile/button`](https://developer.salesforce.com/docs/platform/hxl/references/hxl-reference-about/button.md) or [`tile/link`](https://developer.salesforce.com/docs/platform/hxl/references/hxl-reference-about/link.md) instead.
To create a badge, provide a short label. A label without a variant displays the badge in the default style.
```json
{
"definition": "tile/badge",
"attributes": {
"label": "Basic",
"variant": "success"
}
}
```
To present the badge with a different style, use the `variant` attribute. For example, use `"variant": "success"` to convey a positive status.
```json
{
"definition": "tile/badge",
"attributes": {
"label": "Active",
"variant": "success"
}
}
```
To annotate a name or title with a status label, place `tile/badge` inline with `tile/text` in a `tile/row`.
```json
{
"definition": "tile/row",
"attributes": { "align": "center", "gap": "sm" },
"children": [
{
"definition": "tile/text",
"attributes": { "text": "Acme Corp" }
},
{
"definition": "tile/badge",
"attributes": { "label": "New", "variant": "primary" }
}
]
}
```
## Variants
Use these `variant` values to express different badge states.
- `error`: Indicates an urgent or critical status.
- `info`: Indicates informational status that's useful for supplemental items.
- `outline`: Indicates a subtle status to describe items that are less prominent but helpful.
- `primary`: Indicates non-urgent information for general statuses that don't require immediate attention.
- `secondary` (default): Indicates a neutral label without status emphasis, for general categorization and tags.
- `success`: Indicates a positive status to highlight successful actions or items.
- `warning`: Indicates a cautionary or advisory status to represent items that need action or review but aren't critical.
Consider these guidelines when working with badges.
- Keep labels short. Use one or two words to convey the intent of the badge. Consider using [`tile/text`](https://developer.salesforce.com/docs/platform/hxl/references/hxl-reference-about/text.md) for longer text.
- Use status variants (`"success"`, `"warning"`, `"error"`, `"info"`) only when the label communicates a meaningful state, not for decorative color.
- Use `"primary"` for high-emphasis labels such as "New" or "Featured"; use `"outline"` for a subtle bordered appearance.
## Limitations
Note any limitations that apply to this component.
### Slackbot
No known limitations for `tile/badge` in Slackbot.
### ChatGPT
No known limitations for `tile/badge` in ChatGPT.
### Agentforce
Semantic `variant` colors rely on SLDS styling hooks. Without the styling hooks, badges fall back to the default gray styling.
## See Also
- [HXL Lightning Types Reference](https://developer.salesforce.com/docs/platform/hxl/references/hxl-lightning-types.md)
- [_HXL Playground_: Badge](https://www.headlessexperiencelayer.com/#components/badge)
# 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](https://developer.salesforce.com/docs/platform/hxl/guide/hxl-widget-composition.md), [widget configuration file](https://developer.salesforce.com/docs/platform/hxl/guide/hxl-widget-configuration.md), and optional [schema file](https://developer.salesforce.com/docs/platform/hxl/guide/hxl-widget-schema.md). See [UiWidgetBundle](https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_uiwidgetbundle.htm).
For a detailed example of this structure, see [Example: Mapping a Hotel Card Widget](https://developer.salesforce.com/docs/platform/hxl/guide/hxl-widget-example-mapping.md).
### 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`.
```xml
hotelCard
UiWidgetBundle
67.0
```
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](https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/file_based_zip_file.htm)
- _Metadata API Developer Guide_: [Deleting Components from an Organization](https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_deploy_deleting_files.htm)
### 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](https://developer.salesforce.com/docs/atlas.en-us.sfdx_cli_reference.meta/sfdx_cli_reference/cli_reference_project_commands_unified.htm#cli_reference_project_commands_unified) in the Salesforce CLI Command Reference.
This example shows how to deploy a UiWidgetBundle called `hotelCard` to an org with alias `my-org`:
```
sf project deploy start --metadata UiWidgetBundle:hotelCard --target-org my-org
```
## Connect 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.
**note:** 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.
### 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`, and `outputValues`.
- The **MCP payload custom Lightning type** defines the structure referenced by the MCP result wrapper custom Lightning type’s `outputValues` property.
The terms [MCP result wrapper custom Lightning type](https://developer.salesforce.com/docs/platform/hxl/references/hxl-reference-about/hxl-widgets-glossary.md#mcp-result-wrapper-custom-lightning-type) and [MCP payload custom Lightning type](https://developer.salesforce.com/docs/platform/hxl/references/hxl-reference-about/hxl-widgets-glossary.md#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](https://developer.salesforce.com/docs/platform/lightning-types/guide/lightning-types-apex.html) and [Object-Based Custom Lightning Types](https://developer.salesforce.com/docs/platform/lightning-types/guide/lightning-types-object.html).
### 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 named `hotelCard` in your org’s namespace.
This example shows a basic widget reference:
```json
{
"renderer": {
"componentOverrides": {
"$": {
"definition": "@widget/c/hotelCard"
}
}
}
}
```
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.
**note:** 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)](https://developer.salesforce.com/docs/platform/lightning-types/guide/lightning-types-core.html#lightning-type-structure-for-hxl-widgets-beta).
### 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.json` file.
- 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.
**note:** 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.
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.
```json
{
"renderer": {
"componentOverrides": {
"$": {
"definition": "@widget/c/hotelCard",
"attributes": {
"hotelId": "{!$attrs.hotelId}",
"name": "{!$attrs.name}",
"city": "{!$attrs.city}",
"checkInTime": "{!$attrs.checkInTime}",
"checkOutTime": "{!$attrs.checkOutTime}",
"pricePerNight": "{!$attrs.pricePerNight}",
"rating": "{!$attrs.rating}"
}
}
}
}
}
```
In this example:
- The keys (`hotelId`, `name`, `city`, `checkInTime`, `checkOutTime`, `pricePerNight`, and `rating`) are attributes defined in the widget’s `schema.json` file.
- 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](https://developer.salesforce.com/docs/platform/lightning-types/guide/lightning-types-apex.html).
#### 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.
```json
{
"renderer": {
"componentOverrides": {
"$": {
"definition": "@widget/c/hotelCard",
"attributes": {
"hotelId": "{!$attrs.outputValues.hotelInfo.hotelId}",
"name": "{!$attrs.outputValues.hotelInfo.name}",
"city": "{!$attrs.outputValues.hotelInfo.city}",
"checkInTime": "{!$attrs.outputValues.hotelInfo.checkInTime}",
"checkOutTime": "{!$attrs.outputValues.hotelInfo.checkOutTime}",
"pricePerNight": "{!$attrs.outputValues.hotelInfo.pricePerNight}",
"rating": "{!$attrs.outputValues.hotelInfo.rating}"
}
}
}
}
}
```
In this example:
- The keys (`hotelId`, `name`, `city`, `checkInTime`, `checkOutTime`, `pricePerNight`, and `rating`) are attributes defined in the widget’s `schema.json` file.
- `$attrs.outputValues` references the `outputValues` property in the MCP result wrapper custom Lightning type. The `lightning:type` value of this property references the MCP payload custom Lightning type.
- `hotelInfo` is a property defined in the MCP payload custom Lightning type. Its `lightning:type` value references the `HotelSearchResult.Hotel` Apex class.
- The final segment of each property reference, such as `hotelId`, `name`, or `rating`, references a field in the `HotelSearchResult.Hotel` Apex 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](https://developer.salesforce.com/docs/platform/hxl/guide/hxl-rich-ui.md#configure-custom-lightning-types-for-an-mcp-server-tool).
**See Also**
- [Get Started with Lightning Types](https://developer.salesforce.com/docs/platform/lightning-types/guide/lightning-types.html)
- [Example: Mapping a Hotel Card Widget for Agentforce](https://developer.salesforce.com/docs/platform/hxl/guide/hxl-widget-example-mapping.md)
- [Example: Mapping a Hotel Card Widget for MCP](https://developer.salesforce.com/docs/platform/hxl/guide/hxl-widget-example-mapping-mcp.md)
## 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](https://developer.salesforce.com/docs/platform/lightning-types/guide/lightning-types-object.html).
### 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.
```json
{
"title": "Hotel Info Output Values",
"description": "Payload fields from the HotelSearchResult response",
"type": "object",
"lightning:type": "lightning__objectType",
"lightning:tags": ["mcp"],
"unevaluatedProperties": false,
"properties": {
"hotelInfo": {
"title": "Hotel Info",
"lightning:type": "@apexClassType/c__HotelSearchResult$Hotel"
}
}
}
```
For an MCP payload custom Lightning type:
- Set type to `object`.
- Set `lightning:type` to `lightning__objectType`.
- Include `mcp` in `lightning:tags`.
- Set `unevaluatedProperties` to `false`.
- 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. Its `lightning:type` value references the MCP payload custom Lightning type.
```json
{
"title": "Hotel Info Result",
"description": "Invocable-action result envelope for the HotelSearchResult MCP tool",
"type": "object",
"lightning:type": "lightning__objectType",
"lightning:tags": ["mcp"],
"unevaluatedProperties": false,
"properties": {
"actionName": { "title": "Action Name", "lightning:type": "lightning__textType" },
"isSuccess": { "title": "Is Success", "lightning:type": "lightning__booleanType" },
"outputValues": { "title": "Output Values", "lightning:type": "c__hotelInfoOutputValues" }
}
}
```
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.
```json
{
"renderer": {
"componentOverrides": {
"$": {
"definition": "@widget/c/hotelCard",
"attributes": {
"hotelId": "{!$attrs.outputValues.hotelInfo.hotelId}",
"name": "{!$attrs.outputValues.hotelInfo.name}",
"city": "{!$attrs.outputValues.hotelInfo.city}",
"checkInTime": "{!$attrs.outputValues.hotelInfo.checkInTime}",
"checkOutTime": "{!$attrs.outputValues.hotelInfo.checkOutTime}",
"pricePerNight": "{!$attrs.outputValues.hotelInfo.pricePerNight}",
"rating": "{!$attrs.outputValues.hotelInfo.rating}"
}
}
}
}
}
```
In this example:
- The keys (`hotelId`, `name`, `city`, `checkInTime`, `checkOutTime`, `pricePerNight`, and `rating`) are attributes defined in the `hotelCard` widget’s `schema.json` file.
- `outputValues` is a property in the MCP result wrapper custom Lightning type.
- `hotelInfo` is a property in the MCP payload custom Lightning type.
- The final segment of each expression references a property in the `HotelSearchResult.Hotel` Apex 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`.
```
myProject/
force-app/
main/
default/
uiWidgets/
hotelCard/
hotelCard.json
hotelCard.uiwidget-meta.xml
schema.json
lightningTypes/
hotelInfoResult/
schema.json
renderer.json
hotelInfoOutputValues/
schema.json
```
In this structure:
- `hotelInfoOutputValues` is the bundle for the MCP payload custom Lightning type.
- `hotelInfoResult` is the bundle for the MCP result wrapper custom Lightning type.
- The `hotelInfoResult` bundle contains `renderer.json`.
- `hotelCard` is the widget bundle.
**See Also**
- [Use HXL Widgets on MCP Channels](https://developer.salesforce.com/docs/platform/hxl/guide/hxl-mcp-channels.md)
- [Example: Mapping a Hotel Card Widget for MCP](https://developer.salesforce.com/docs/platform/hxl/guide/hxl-widget-example-mapping-mcp.md)
## 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.
```json
{
"renderer": {
"componentOverrides": {
"$": {
"definition": "@widget/c/hotelCard"
}
}
}
}
```
**See Also**
- [Get Started with Lightning Types](https://developer.salesforce.com/docs/platform/lightning-types/guide/lightning-types.html)
- [Core Concepts of Custom Lightning Types](https://developer.salesforce.com/docs/platform/lightning-types/guide/lightning-types-core.html)
# Button
**`tile/button`**
Shows a clickable element that triggers an action. A button includes semantic and visual variants, optional icon decoration, and the loading state.
## Properties
| Name | Required | Lightning Type | Default | Description |
| ---- | -------- | -------------- | ------- | ----------- |
| actions | No | `lightning__textType` | | Actions invoked by user interaction, keyed by event name. |
| iconName | No | `lightning__iconName` | | A semantic icon identifier shown next to the label. |
| label | Yes | `lightning__textType` | | The required text string for the button. |
| variant | No | `lightning__textType` | `primary` | Changes the appearance of the button. Valid values include `primary` for main actions, `secondary` for supporting actions, or `destructive` for dangerous actions. |
## Usage
Use a button for a user-initiated action. For the main call-to-action, use the `primary` variant. Use the `secondary` variant for supporting actions, and `destructive` for irreversible or dangerous actions. Avoid placing two primary buttons side by side.
**note:** To create a link for navigation, use [`tile/link`](https://developer.salesforce.com/docs/platform/hxl/references/hxl-reference-about/link.md) instead.
To reinforce the action, add an `iconName`. The value is an identifier such as `edit`, `trash`, or `plus`, which maps to an icon on each surface.
```json
{
"definition": "tile/button",
"attributes": { "label": "Delete", "variant": "destructive", "iconName": "trash" }
}
```
To lay out multiple buttons horizontally, wrap the buttons with [`tile/row`](https://developer.salesforce.com/docs/platform/hxl/references/hxl-reference-about/row.md).
```json
{
"definition": "tile/row",
"attributes": { "gap": "sm" },
"children": [
{
"definition": "tile/button",
"attributes": { "label": "Save", "variant": "primary" }
},
{
"definition": "tile/button",
"attributes": { "label": "Cancel", "variant": "secondary" }
}
]
}
```
## Variants
Use these `variant` values to convey the button's role and emphasis.
- `primary` (default): The main call-to-action in a view, such as "Save" or "Submit". Use one primary button per group of actions.
- `secondary`: A supporting action paired alongside a primary button, such as "Cancel" next to "Save".
- `destructive`: An irreversible or dangerous action, such as deleting a record or canceling a subscription.
## Design Guidelines
Consider these guidelines when working with buttons.
- Keep labels short and action-oriented, for example, "Save" or "Send Message".
- Pick an `iconName` that reinforces the label rather than replaces it; the label is always required, even for icon-led buttons.
## Limitations
Note any limitations that apply to this component.
### Slackbot
No known limitations for `tile/button` in Slackbot.
### ChatGPT
No known limitations for `tile/button` in ChatGPT.
### Agentforce
No known limitations for `tile/button` in Agentforce.
## See Also
- [HXL Lightning Types Reference](https://developer.salesforce.com/docs/platform/hxl/references/hxl-lightning-types.md)
- [_HXL Playground_: Button](https://www.headlessexperiencelayer.com/#components/button)
# Callout
**`tile/callout`**
Highlights a content block for emphasis. The callout wraps child content with a semantic variant, optional title, and description.
## Properties
| Name | Required | Lightning Type | Default | Description |
| ---- | -------- | -------------- | ------- | ----------- |
| description | No | `lightning__textType` | | The body text below the title. |
| iconAlt | No | `lightning__textType` | | Alternative text describing what the leading variant icon conveys. When omitted or empty, the icon is treated as decorative and hidden from assistive technologies. |
| title | Yes | `lightning__textType` | | The heading text for the callout block. |
| variant | No | `lightning__textType` | `default` | Changes the appearance of the callout. Valid values include `default` for neutral, `error` for a critical issue, `info` for context, `note` for an aside, `success` for a positive outcome, `tip` for a suggestion, or `warning` for caution. |
## Usage
Use a callout to draw attention to a piece of information that stands apart from the surrounding content, such as a tip, a warning, or a confirmation. It renders a titled block with a colored border, background tint, and icon set by its `variant`.
**note:** A callout is a container, so it can wrap richer body content as child blocks. For a plain run of body text with no emphasis, use [`tile/text`](https://developer.salesforce.com/docs/platform/hxl/references/hxl-reference-about/text.md) instead.
To create a callout, set a short `title` and choose a `variant` that matches the message. Use `description` for a single line of supporting body text.
```json
{
"definition": "tile/callout",
"attributes": {
"title": "Did you know?",
"description": "This feature is available in all plans.",
"variant": "info"
}
}
```
To flag something that's critical, use the `warning` or `error` variant.
```json
{
"definition": "tile/callout",
"attributes": {
"title": "Important Notice",
"description": "This action cannot be undone.",
"variant": "warning"
}
}
```
For richer body content, omit `description` and provide child blocks instead. The children render below the title inside the callout.
```json
{
"definition": "tile/callout",
"attributes": {
"title": "Additional Information",
"variant": "note"
},
"children": [
{
"definition": "tile/text",
"attributes": { "text": "Review the steps below before continuing." }
}
]
}
```
## Variants
Use `variant` to set the callout's semantic category, which determines its color, background tint, and icon. On text-only surfaces, the variant is conveyed with a label prefix such as "Warning:" instead of color.
- `default`: The default neutral styling with no specific status.
- `error`: A critical failure or blocking issue, which shows something that went wrong and needs attention.
- `info`: Supplementary context or background, which adds helpful detail that isn't urgent.
- `note`: A general aside or clarification, which shows a remark that sits alongside the main content.
- `success`: A positive outcome or confirmation, which confirms that an action completed.
- `tip`: A helpful suggestion or best practice, which provides a recommendation for something.
- `warning`: A potential issue or caution, which notifies the user before they take a risky action.
## Design Guidelines
Consider these guidelines when working with callouts.
- Choose a `variant` that matches the message's tone as the variant carries the meaning even when color isn't available.
- Use `description` for a single line of body text, and switch to child blocks when the content needs structure such as a list or code.
- Reserve callouts for information that genuinely needs to stand out.
## Limitations
Note any limitations that apply to this component.
### Slackbot
No known limitations for `tile/callout` in Slackbot.
### ChatGPT
No known limitations for `tile/callout` in ChatGPT.
### Agentforce
No known limitations for `tile/callout` in Agentforce.
## See Also
- [HXL Lightning Types Reference](https://developer.salesforce.com/docs/platform/hxl/references/hxl-lightning-types.md)
- [_HXL Playground_: Callout](https://www.headlessexperiencelayer.com/#components/callout)
# Code
**`tile/code`**
Shows preformatted source code content with an optional language label.
## Properties
| Name | Required | Lightning Type | Default | Description |
| ---- | -------- | -------------- | ------- | ----------- |
| code | Yes | `lightning__multilineTextType` | | The source code text string, which includes any programming or markup language. |
| language | No | `lightning__textType` | | A programming language identifier shown as a header label. For example: `javascript`, `python`, `sql`. |
## Usage
Display a block of preformatted source code in a monospace font, preserving whitespace, indentation, and line breaks exactly as written. Use `tile/code` to show a snippet, command, config file, or query.
**note:** For inline code within a sentence, use [`tile/text`](https://developer.salesforce.com/docs/platform/hxl/references/hxl-reference-about/text.md) with `variant: "code"` instead. For rich-formatted content, use [`tile/markdown`](https://developer.salesforce.com/docs/platform/hxl/references/hxl-reference-about/markdown.md) instead.
Embed newlines as `\n` and include any indentation directly in the `code` string. Whitespace is preserved exactly as you entered it.
```json
{
"definition": "tile/code",
"attributes": {
"code": "const greeting = 'Hello, World!';\nconsole.log(greeting);",
"language": "javascript"
}
}
```
When the snippet doesn't match a supported language, omit `language` to hide the header.
```json
{
"definition": "tile/code",
"attributes": {
"code": "some_command --flag value\nanother_command | pipe_to_here"
}
}
```
## Languages
Use the `language` attribute with these languages.
- `javascript`
- `typescript`
- `python`
- `java`
- `c`
- `cpp`
- `csharp`
- `go`
- `rust`
- `ruby`
- `php`
- `sql`
- `html`
- `css`
- `json`
- `yaml`
- `xml`
- `bash`
- `markdown`
Consider these guidelines when working with code.
- Set `language` to a lowercase identifier such as `"python"` or `"sql"`, so the header label appears.
- Code highlighting isn't supported.
## Limitations
Note any limitations that apply to this component.
### Slackbot
No known limitations for `tile/code` in Slackbot.
### ChatGPT
No known limitations for `tile/code` in ChatGPT.
### Agentforce
`language` isn't supported. The code block renders as monospace text without syntax highlighting.
## See Also
- [HXL Lightning Types Reference](https://developer.salesforce.com/docs/platform/hxl/references/hxl-lightning-types.md)
- [_HXL Playground_: Code](https://www.headlessexperiencelayer.com/#components/code)
# Column
**`tile/column`**
Arranges child components vertically with a configurable gap, cross-axis alignment, and width.
## Properties
| Name | Required | Lightning Type | Default | Description |
| ---- | -------- | -------------- | ------- | ----------- |
| align | Yes | `lightning__alignmentType` | | The cross-axis alignment of children within the column. Valid values include `start`, `center`, `end`, or `stretch` (default). |
| gap | Yes | `lightning__gapType` | | The spacing between child components. Valid values include `none` for zero, `xs` through `xl` for increasing space. The default is `md` for medium. |
| width | No | `lightning__extentType` | | The horizontal space the column occupies. Valid values include `auto` for content-sized, `xs` through `xl` for fixed widths, `full` for 100%, `stretch` to fill remaining space. |
## Usage
Stack child tiles vertically, top to bottom, with consistent spacing between them. Use a column to make content flow down the page. For example, a column can include a heading before body text that precedes a button.
```json
{
"definition": "tile/column",
"children": [
{
"definition": "tile/text",
"attributes": { "text": "Column Header", "variant": "h3" }
},
{
"definition": "tile/text",
"attributes": { "text": "Vertically stacked content." }
},
{
"definition": "tile/button",
"attributes": { "label": "Action", "variant": "primary" }
}
]
}
```
To build multi-column layouts where each column controls its own `width`, use
the column with [`tile/row`](https://developer.salesforce.com/docs/platform/hxl/references/hxl-reference-about/row.md). Use `gap` for uniform spacing between all child content. Place each column inside `tile/row` for a side-by-side layout. Give each column a `width` to control how it shares the horizontal space.
```json
{
"definition": "tile/row",
"attributes": { "gap": "sm" },
"children": [
{
"definition": "tile/column",
"attributes": { "width": "md" },
"children": [
{ "definition": "tile/text", "attributes": { "text": "Left", "variant": "h5" } }
]
},
{
"definition": "tile/column",
"attributes": { "width": "stretch" },
"children": [
{ "definition": "tile/text", "attributes": { "text": "Right", "variant": "h5" } }
]
}
]
}
```
## Alignment
Use these `align` values to specify how the column positions the content. This attribute applies to all child content uniformly.
- `start`: Content aligns to the leading edge.
- `center`: Content centers horizontally.
- `end`: Content aligns to the trailing edge.
- `stretch`: Content expands to fill the full column width.
## Width
Use these `width` values to specify the content width in a column. By default, the column has no width constraint and behaves like `auto`. The width can vary across surfaces.
- `auto`: Content sizes automatically with no explicit width constraint.
- `xs`: Extra small fixed width, or 3 out of a 12-column grid.
- `sm`: Small fixed width, or 4 out of a 12-column grid.
- `md`: Medium fixed width, or 6 out of a 12-column grid.
- `lg`: Large fixed width, or 8 out of a 12-column grid.
- `xl`: Extra large fixed width, or 9 out of a 12-column grid.
- `full`: Takes 100% of the parent width. Use `full` for single-column layouts or to make the column occupy the entire line.
- `stretch`: Grows to fill remaining available space in the parent, which is similar to the flex-grow behavior. Use `stretch` for fluid layouts like the sidebar or main content. Multiple columns that use `stretch` in the same row share remaining space equally.
## Design Guidelines
Consider these guidelines when working with columns.
- For a one-off gap between two specific children, insert a [`tile/spacer`](https://developer.salesforce.com/docs/platform/hxl/references/hxl-reference-about/spacer.md) instead.
- Use [`tile/row`](https://developer.salesforce.com/docs/platform/hxl/references/hxl-reference-about/row.md) to make content flow left to right rather than top to bottom.
- Set `align` to `center` to horizontally center children, or leave it at the default for the child content to fill the column width.
- Inside a row, give one column `width: "stretch"` so it absorbs the remaining space while the sibling rows stay content-sized.
## Limitations
Note any limitations that apply to this component.
### Slackbot
No known limitations for `tile/column` in Slackbot.
### ChatGPT
No known limitations for `tile/column` in ChatGPT.
### Agentforce
No known limitations for `tile/column` in Agentforce.
## See Also
- [HXL Lightning Types Reference](https://developer.salesforce.com/docs/platform/hxl/references/hxl-lightning-types.md)
- [_HXL Playground_: Column](https://www.headlessexperiencelayer.com/#components/column)
# 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.
| Property | Type | Required or Optional | Description |
| ------------------------ | ------ | -------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `type` | String | Required | The content type identifier. Set this to `lightning__agentforceWidget`. This identifier applies to all supported Salesforce applications and platforms. |
| `contentBody` | Object | Required | The root content object containing the composition structure. |
| `contentBody.widgetBody` | Object | Required | The 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.
```json
{
"type": "lightning__agentforceWidget",
"contentBody": {
"widgetBody": {
"definition": "tile/widget",
"children": [
{
"definition": "tile/card",
"attributes": {
"padding": "lg",
"variant": "default",
"maxWidth": "full"
},
"children": [
{
"definition": "tile/image",
"attributes": {
"src": "{!$attrs.imageUrl}",
"alt": "{!$attrs.title}"
}
},
{
"definition": "tile/text",
"attributes": {
"text": "{!$attrs.title}",
"variant": "h3",
"weight": "semibold"
}
},
{
"definition": "tile/text",
"attributes": {
"text": "{!$attrs.price}",
"variant": "body",
"weight": "medium"
}
},
{
"definition": "tile/text",
"attributes": {
"text": "{!$attrs.description}",
"variant": "body"
}
}
]
}
]
}
}
}
```
## 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](https://help.salesforce.com/s/articleView?id=xcloud.security_trusted_urls_manage.htm&type=5) in your org. After you set up the Trusted URL, Salesforce automatically provisions the [Content Security Policy](https://help.salesforce.com/s/articleView?id=xcloud.shr_content_security_policy_csp_directive_rendering.htm&type=5) setting for the MCP server.
## Use Salesforce Formulas in Widgets
Widget composition supports a formula language based on the [Salesforce formula engine](https://github.com/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](https://learnexperiencecloud.my.site.com/playground/#06-formulas) 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.
| Property | Required or optional | Description |
| :--------- | :------------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `if` | Optional | References 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}`. |
| `forEach` | Optional | References the collection whose items the component renders. |
| `forItem` | Optional | Defines the variable used to reference the current item. The value must begin with `$`. If omitted, the value defaults to `$Item`. |
| `forIndex` | Optional | Defines 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`.
```json
{
"definition": "tile/text",
"meta": {
"if": "{!$attrs.isVerified}"
},
"attributes": {
"text": "Verified hotel",
"variant": "body"
}
}
```
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.
```json
{
"definition": "tile/text",
"meta": {
"if": "{!AND($attrs.isAvailable, $attrs.price < 500)}"
},
"attributes": {
"text": "Available within budget",
"variant": "body"
}
}
```
### 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.
```json
{
"definition": "tile/text",
"meta": {
"forEach": "{!$attrs.amenities}",
"forItem": "$amenity"
},
"attributes": {
"text": "{!$amenity.name}",
"variant": "body"
}
}
```
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.
```json
{
"definition": "tile/text",
"meta": {
"forEach": "{!$attrs.amenities}"
},
"attributes": {
"text": "{!$Item.name}",
"variant": "body"
}
}
```
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:
```json
{
"definition": "tile/text",
"meta": {
"forEach": "{!$attrs.amenities}",
"forItem": "$amenity",
"forIndex": "$amenityIndex"
},
"attributes": {
"text": "{!$amenity.name}",
"variant": "body"
}
}
```
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`.
```json
{
"definition": "tile/text",
"meta": {
"forEach": "{!$attrs.amenities}",
"forItem": "$amenity",
"if": "{!$amenity.isAvailable}"
},
"attributes": {
"text": "{!$amenity.name}",
"variant": "body"
}
}
```
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`.
```json
{
"definition": "tile/text",
"meta": {
"forEach": "{!$attrs.amenities}",
"forItem": "$amenity",
"if": "{!$attrs.showAmenities}"
},
"attributes": {
"text": "{!$amenity.name}",
"variant": "body"
}
}
```
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.
**note:** 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.
**See Also**
- [HXL Components](https://developer.salesforce.com/docs/platform/reference/about-hxl-components.md#components)
# Connect Your MCP Client to Your Org
The process for connecting MCP clients to use your HXL widget differs depending on the client.
## Connect Claude Desktop or ChatGPT
Connect Claude Desktop or ChatGPT as MCP clients by adding the custom MCP server URL and ECA consumer key that you previously noted. For details, see:
- [Configure Claude](https://developer.salesforce.com/docs/platform/hosted-mcp-servers/guide/claude.html)
- [Configure ChatGPT](https://developer.salesforce.com/docs/platform/hosted-mcp-servers/guide/chatgpt.html)
## Connect Slackbot
To render your widget in Slackbot, add and configure your custom Salesforce MCP server in Slack.
For complete details, see [Connecting an MCP server to the Slackbot MCP Client](https://docs.slack.dev/ai/slackbot-mcp-client/). These options are relevant for Salesforce MCP servers:
- **Auth Type**: Specify Manual OAuth.
- **URL**: Specify the MCP Server URL you noted previously, such as `https://api.salesforce.com/platform/mcp/v1/custom/HotelInfoMCPServer`.
- **Client ID**: When configuring the OAuth provider, specify the consumer key you noted when you configured the external client app (ECA) in your org.
**warning:** HXL widgets don't currently render when using [Block Kit for Slackbot](https://docs.slack.dev/block-kit/). Block Kit extends the [MCP Apps protocol](https://modelcontextprotocol.io/extensions/apps/overview) so MCP servers can return native Slack Block Kit JSON when Slackbot is the client.
## Test the Widget on Your MCP Client
After you connect your MCP client to your org, test that the widget renders the data correctly by running a prompt that invokes it. Each client is different, though most have a chatbot window or UI element where you can enter a prompt.
For example, to see the hotel info widget in action, try this prompt:
_Tell me about the Four Seasons Resort in Maui._
**warning:** If you update your widget in your org after you've rendered it on an MCP client, it can take a while for the updated widget to refresh on the MCP client.
For more robust testing, check out [MCPJam](https://www.mcpjam.com/) which helps you test, debug, and evaluate MCP servers, MCP apps, and ChatGPT apps.
## See Also
- [Salesforce Dev Blog: Connect Claude with Salesforce Hosted MCP Servers](https://developer.salesforce.com/blogs/2026/05/connect-claude-with-salesforce-hosted-mcp-servers)
- [Salesforce Hosted MCP Servers](https://developer.salesforce.com/docs/platform/hosted-mcp-servers/guide/hosted-mcp-servers-overview.html)
- [Connecting an MCP server to the Slackbot MCP Client](https://docs.slack.dev/ai/slackbot-mcp-client/)
# Container
**`tile/container`**
Creates a container with a rounded border that accepts any children.
## Properties
| Name | Required | Lightning Type | Default | Description |
| ---- | -------- | -------------- | ------- | ----------- |
| borderless | No | `lightning__booleanType` | false | Specifies whether the container omits its border. |
| variant | No | `lightning__textType` | `default` | Sets the visual variant of the container. |
## Usage
Use a container to group related children inside a rounded, padded border. The container provides a card-like frame that visually separates a block of content from surrounding content.
To control layout in a container, use [`tile/column`](https://developer.salesforce.com/docs/platform/hxl/references/hxl-reference-about/column.md) or [`tile/row`](https://developer.salesforce.com/docs/platform/hxl/references/hxl-reference-about/row.md). Wrap children content in a `tile/column` for vertical stacking or a `tile/row` for a horizontal arrangement. Use the `gap` attribute to space them.
```json
{
"definition": "tile/container",
"children": [
{
"definition": "tile/column",
"attributes": { "gap": "sm" },
"children": [
{
"definition": "tile/text",
"attributes": { "text": "Container", "variant": "h2" }
},
{
"definition": "tile/text",
"attributes": { "text": "A framed region that groups related content." }
},
{
"definition": "tile/button",
"attributes": { "label": "Action", "variant": "primary" }
}
]
}
]
}
```
**note:** For grouping that needs no frame at all, use a `tile/column` or `tile/row` directly instead of a borderless container.
To remove the border on the container, set `borderless` to `true`.
```json
{
"definition": "tile/container",
"attributes": { "borderless": true },
"children": [
{
"definition": "tile/text",
"attributes": { "text": "A flat, frameless region." }
}
]
}
```
## Variant
Set `variant` to tint the container's fill. Use it to group or emphasize a region, or to signal status. The default is `default`, which matches the surrounding background (no fill).
| Value | Appearance | Use for |
| ---------- | ----------------------------------------------------- | ----------------------------------------------- |
| `default` | Matches the surrounding background (no fill) | The normal, unemphasized case |
| `emphasis` | A subtle neutral shade, slightly darker than the page | Setting a region apart without a status meaning |
| `info` | Blue | Informational or in-progress content |
| `warning` | Yellow | Cautions the user should notice |
| `error` | Red | Problems or destructive context |
| `success` | Green | Confirmations or completed states |
The four status colors (`info`, `warning`, `error`, `success`) also tint the border to match the fill.
```json
{
"definition": "tile/container",
"attributes": { "variant": "info" },
"children": [
{
"definition": "tile/text",
"attributes": { "text": "Your changes are still syncing." }
}
]
}
```
## Design Guidelines
Consider these guidelines when working with containers.
- To arrange the children inside, nest a `tile/column` or `tile/row` rather than relying on the container itself.
- Set `borderless` to `true` when a container is nested inside another framed surface, so the borders don't stack and compete.
- Avoid deeply nesting framed containers. Stacked borders and padding crowd the content in smaller screens.
- Reach for a status `variant` (`info`, `warning`, `error`, `success`) only when the color carries meaning — and always convey that meaning in the container's text content (e.g. a `tile/text` heading like "Warning" or "Completed with errors"), never through color alone (WCAG 2.2 SC 1.4.1, Use of Color). For a single titled status message with an icon, prefer `tile/callout`; use a tinted container to frame a broader region of content.
- Use `emphasis` for a neutral emphasis that groups content without implying a status.
## Limitations
Note any limitations that apply to this component.
### Slackbot
No known limitations for `tile/container` in Slackbot.
### ChatGPT
No known limitations for `tile/container` in ChatGPT.
### Agentforce
No known limitations for `tile/container` in Agentforce.
## See Also
- [HXL Lightning Types Reference](https://developer.salesforce.com/docs/platform/hxl/references/hxl-lightning-types.md)
- [_HXL Playground_: Container](https://www.headlessexperiencelayer.com/#components/container)
# Create a Custom Salesforce MCP Server
To use HXL widgets on channels that support MCP (Claude Desktop, Slackbot, and ChatGPT), you need a custom MCP server. You can also update an existing custom MCP server if you prefer.
**note:** You use Setup in your org to create an MCP server. But Setup doesn't currently support configuring the server with HXL resources. After creating the MCP server, retrieve its metadata to your DX project, update the metadata file, and then deploy it back to your org, as described in this topic.
1. In your org's Setup UI, enter `MCP` in the Quick Find box and select **MCP Servers** under **API Catalog**.
1. Click **Add MCP Server**, enter the basic information, and then click **Create**.
To modify an existing MCP server, click it in the table.
**important:** Note the MCP Server URL because you'll use it later to configure your MCP client. The URL looks something like `https://api.salesforce.com/platform/mcp/v1/custom/getHotelDetailsMcpServer`.
1. Click **Add Server Assets > Add Tools**.
1. Select **Apex actions** from the dropdown menu on the left, select the Apex invocable action you previously created, and then click **+ Add Tool**. When you're satisfied, click **Save**.

1. In your local DX project, retrieve the metadata file associated with your new MCP server. This example uses the `project` Salesforce CLI command, assumes your MCP server is called `getHotelDetailsMcpServer`, and that you're retrieving from an org with alias `my-org`:
```bash
sf project retrieve start --metadata McpServerDefinition:getHotelDetailsMcpServer --target-org my-org
```
The CLI command retrieves the metadata source to this location in your DX project: `force-app/main/default/mcpServerDefinitions/getHotelDetailsMcpServer.mcpServerDefinition-meta.xml`.
1. Open the MCP server metadata file (such as `getHotelDetailsMcpServer.mcpServerDefinition-meta.xml`) in your IDE and update it by adding the widget resource and then associating it to the MCP tool.
1. Add a `` XML element alongside the `` element and add these child elements that describe your widget:
- ``: The name of this widget resource. You can use any name; the `` section uses the name to reference this resource.
- ``: The URI of the widget. Use this format: `ui://widget/lightningType/`. For example, `ui://widget/lightningType/c__hotelInfoResult`.
- ``: The title of the widget resource.
- ``: The description of the widget resource.
1. Add a child `` element to the `` element that references the `` of the new widget resource you just added. For example:
`hotelDetails`
**Important**: Be sure that the value of the `` element exactly matches the value of the `` element for the widget `` entry. Otherwise your widget won't render correctly.
Here's an example of an updated MCP server metadata file:

1. Deploy the updated MCP server definition back to your org. Here's a Salesforce CLI example:
```bash
sf project deploy start --metadata McpServerDefinition:getHotelDetailsMcpServer --target-org my-org
```
1. Back in your org's Setup UI, navigate to the details page for your custom MCP server and click **Activate** to activate it.
You're now ready to configure your org so MCP clients can access it. See [Set Up Your Org for MCP Access](https://developer.salesforce.com/docs/platform/hxl/guide/hxl-mcp-setup-org.md).
## See Also
- [Salesforce Hosted MCP Servers](https://developer.salesforce.com/docs/platform/hosted-mcp-servers/guide/hosted-mcp-servers-overview.html)
- [Workshop: Explore Salesforce Hosted MCPs](https://developer.salesforce.com/workshops/headless-360-workshop/explore-salesforce-hosted-mcps/overview)
- [Salesforce CLI Command Reference: project Commands](https://developer.salesforce.com/docs/platform/salesforce-cli-reference/guide/cli_reference_project.html)
# Create the Apex Invocable Action
Your widget displays data from an object in your org, such as a HotelInfo custom object. While there are multiple ways to get the data, a standard approach is to create an Apex class that contains a SOQL query for the HotelInfo object. The Apex class returns the results in the shape of one of your custom Lightning types schema. You later use this Apex class to create an MCP tool in your custom MCP server.
1. In your local DX project, create the Apex class that queries your org and returns output shaped to the schema of one of your custom Lightning types. Remember, for channels that support MCP, you must create _two_ custom Lightning types: one for the MCP result wrapper role and one for the MCP payload role.
Make sure your Apex code meets the requirements for an Apex invocable action. For example, the Apex class must be `global` and the method that returns results must be annotated with `@InvocableMethod`. See these links for full details:
- [Connect Your Widget to a Custom Lightning Type](https://developer.salesforce.com/docs/platform/hxl/guide/hxl-rich-ui.md#connect-your-widget-to-a-custom-lightning-type) for details about the two required custom Lightning types.
- [Apex Actions](https://developer.salesforce.com/docs/platform/hosted-mcp-servers/guide/invocable-actions.html)
1. Deploy your Apex class to your org. For example, to use a Salesforce CLI command to deploy to the org with alias `my-org`, run this command:
```bash
sf project deploy start --metadata ApexClass:HotelSearchResult --target-org my-org
```
Your Apex invocable action is ready to become an MCP tool. See [Create a Custom MCP Server](https://developer.salesforce.com/docs/platform/hxl/guide/hxl-mcp-server.md).
## See Also
- [Salesforce Dev Blog: Expose Custom Apex as a Hosted MCP Tool for Agents](https://developer.salesforce.com/blogs/2026/05/expose-custom-apex-as-a-hosted-mcp-tool-for-agents)
- [Trailhead: Agent Customization with Apex](https://trailhead.salesforce.com/content/learn/modules/agent-customization-with-apex)
- [Apex Developer Guide](https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/apex_dev_guide.htm)
- [Apex @InvocableMethod Annotation](https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/apex_classes_annotation_InvocableMethod.htm)
- [Apex Actions](https://developer.salesforce.com/docs/platform/hosted-mcp-servers/guide/invocable-actions.html)
- [Custom Lightning Types](https://developer.salesforce.com/docs/platform/lightning-types/guide/lightning-types.html)
- [_Salesforce CLI Command Reference_: project Commands](https://developer.salesforce.com/docs/platform/salesforce-cli-reference/guide/cli_reference_project.html)
# Create Widgets in HXL Playground
The [Widgets](https://www.headlessexperiencelayer.com/#widget/local) page is where you compose components into a complete, reusable UI. Build your widgets in the playground, then copy and paste the JSON in your widget bundle's `.json` composition file.
The left sidebar organizes your work.
- Click **New widget** to create a widget.
- Review the widgets you created under the **My Widgets** section. They're saved locally in your browser, so they persist between visits on the same device.
- Explore widget examples under **Examples** to see dashboards, tables, and other composition patterns.

When you open or create a widget, the main area shows a live preview of the widget's JSON configuration next to the editor. Use the toggle above the editor to render the widget on surfaces such as Agentforce, Slackbot, and ChatGPT.
## Create a New Widget
1. On the **Widgets** page, click **New widget** at the top of the sidebar. Alternatively, on an empty canvas, click **Create your first widget**.
2. Choose how to start:
- **From a template**: Pick a ready-made widget from the template library to use as your starting point.
- **From scratch**: Start with a blank widget and build it up.
3. The new widget opens in the editor under **My Widgets**, with a live preview next to it.
4. Edit the widget's structure and data in the editor. Use the preview toggle to preview the widget on each surface.

To rename a widget, edit its title at the top of the editor. The API name updates automatically.

## Save a Widget
Your widgets appear under **My Widgets**. These widgets save automatically to your browser's local storage as you edit them.
Example and pre-built widgets are read-only. To keep your changes to an example or pre-built widget:
1. Open the example widget you want to modify.
2. Make your edits in the editor by modifying the JSON configuration of the widget.
3. Click **Save**. The playground saves a copy under **My Widgets**, and switches the editor to that copy.
**note:** The **Save** button appears only for example and pre-built widgets. Widgets under **My Widgets** save automatically.
Your widgets persist across browser restarts and reboots. The browser evicts the widget under storage pressure. The browser's local storage is temporary. Browsers can clear local storage for sites that haven't been visited in a long time, or when disk quota is low. The widgets are removed if one of these conditions occurs.
- You clear browsing data such as cookies and cached site data for the site.
- You delete the widget in the playground by clicking the **Delete** button.
- You use a different browser, device, profile, or an incognito session.
**note:** Storage is scoped per origin and per browser profile. Your widgets aren't available on another machine, another browser, or an incognito window, which discards the window's storage when closed. To make a widget available on another machine or browser, use the **Share** button to copy a shareable link.
## Clone a Widget
Cloning creates an independent copy under **My Widgets**, leaving the original untouched. Cloning works for any widget, including your own widgets and examples.
1. Open the widget you want to copy.
2. Click **Clone**.
3. A duplicate named _"<widget> (copy)"_ is created under **My Widgets**, and the editor switches to it. Edit the clone freely without affecting the original.
## Share a Widget
Share a widget as a self-contained link. The link encodes the widget's definition, so the recipient doesn't need access to your browser storage.
1. Open the widget you want to share.
2. Click **Share** to copy a shareable link to your clipboard.
3. Send the link to anyone. When they open it, the widget loads directly into the playground.
## Import a Widget
To import a widget, open a share link that someone sent you. The playground decodes the link and adds the widget to **My Widgets** automatically.
If a widget with the same name already exists in **My Widgets**, the playground asks how to handle the conflict.
- **Update existing** replaces the saved version with the one from the link.
- **Import as copy** keeps both by saving the incoming widget as a new copy.
- **Open existing** ignores the link and opens the version you already have.
Choose **Cancel** to dismiss the prompt without importing.
## Delete a Widget
Delete only widgets that you created under **My Widgets**. Example and pre-built widgets can't be deleted.
1. Open the widget you want to remove.
2. Click **Delete**.
3. The playground removes the widget from **My Widgets** and from your browser's local storage. The editor switches to another saved widget, or to the empty canvas if none remain.
**note:** Deletion is permanent. To back up the widget before deleting it, use **Share** to copy the widget's link, or copy its JSON from the editor.
# Example: Mapping a Hotel Card Widget for Agentforce
This example shows how Agentforce action output rendered in Lightning Experience flows through an Apex-based custom Lightning type named `hotelInfo` to the `hotelCard` widget.
This example uses two schema files that serve different purposes:
- The Lightning type schema describes the data shape—the data structure of hotel information returned by your data source
- The widget schema describes the UI shape—the attribute contract that defines what the card component needs to render
You map the data shape to the UI shape by using the renderer file.
## Before You Begin
Download these sample data files.
- [hotelCardWidget.zip](https://resources.docs.salesforce.com/rel1/doc/en-us/static/misc/HotelCardWidget1.zip)
- [hotelInfoLightningType.zip](https://resources.docs.salesforce.com/rel1/doc/en-us/static/misc/HotelInfoLightningTypes1.zip)
- [hotelSearchResultApexClass.zip](https://resources.docs.salesforce.com/rel1/doc/en-us/static/misc/HotelSearchResultApexClassBundle1.zip)
## Project Directory Workspace Structure
This layout shows where the custom UiWidgetBundle and related LightningTypeBundle component files belong in your Salesforce DX project.
```
myProject/
force-app/
main/
default/
uiWidgets/
hotelCard/
hotelCard.json
hotelCard.uiwidget-meta.xml
schema.json
lightningTypes/
hotelInfo/
schema.json
renderer.json
```
**note:** In this directory structure, `renderer.json` sits directly parallel to `schema.json`. For widget references, create this file at the root level without using channel-specific subfolders. See [Connect Your Widget to a Custom Lightning Type](https://developer.salesforce.com/docs/platform/hxl/guide/hxl-rich-ui.md#connect-your-widget-to-a-custom-lightning-type).
**See Also**
- [UiWidgetBundle](https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_uiwidgetbundle.htm)
## Declare the Widget Attribute Contract
The widget schema file (`uiWidgets/hotelCard/schema.json`) defines the attributes that your widget accepts. These attributes become available as `{!$attrs.attributeName}` bindings in your widget's composition file and as mapping targets in the Lightning type's `renderer.json` file.
```json
{
"title": "Get Hotel Details Widget",
"description": "Displays hotel details including name, city, check-in and check-out times, nightly price, and rating.",
"type": "object",
"properties": {
"attributes": {
"lightning:type": "lightning__objectType",
"properties": {
"hotelId": {
"title": "Hotel ID",
"description": "Unique hotel identifier (e.g. HTL-101)",
"lightning:type": "lightning__textType"
},
"name": {
"title": "Name",
"description": "Hotel name",
"lightning:type": "lightning__textType"
},
"city": {
"title": "City",
"description": "City where the hotel is located",
"lightning:type": "lightning__textType"
},
"checkInTime": {
"title": "Check-In Time",
"description": "Standard check-in time",
"lightning:type": "lightning__textType"
},
"checkOutTime": {
"title": "Check-Out Time",
"description": "Standard check-out time",
"lightning:type": "lightning__textType"
},
"pricePerNight": {
"title": "Price Per Night",
"description": "Nightly price in USD",
"lightning:type": "lightning__numberType"
},
"rating": {
"title": "Rating",
"description": "Guest rating out of 5",
"lightning:type": "lightning__numberType"
}
}
}
}
}
```
**See Also**
- [Schema File](https://developer.salesforce.com/docs/platform/hxl/guide/hxl-widget-schema.md)
## Build the Widget Composition
The composition file (`uiWidgets/hotelCard/hotelCard.json`) defines the widget's visual structure and binds the widget’s schema attributes to UI components by using `{!$attrs.attributeName}` expressions.
```json
{
"type": "lightning__agentforceWidget",
"contentBody": {
"widgetBody": {
"definition": "tile/widget",
"children": [
{
"definition": "tile/column",
"attributes": {
"gap": "md"
},
"children": [
{
"definition": "tile/container",
"children": [
{
"definition": "tile/text",
"attributes": {
"text": "{!$attrs.name}",
"variant": "h2"
}
},
{
"definition": "tile/row",
"attributes": {
"gap": "sm"
},
"children": [
{
"definition": "tile/text",
"attributes": {
"text": "{!$attrs.city}",
"variant": "caption",
"color": "muted"
}
},
{
"definition": "tile/text",
"attributes": {
"text": "•",
"variant": "caption",
"color": "muted"
}
},
{
"definition": "tile/text",
"attributes": {
"text": "{!$attrs.hotelId}",
"variant": "caption",
"color": "muted"
}
}
]
}
]
},
{
"definition": "tile/container",
"children": [
{
"definition": "tile/column",
"attributes": {
"gap": "sm"
},
"children": [
{
"definition": "tile/row",
"attributes": {
"gap": "sm"
},
"children": [
{
"definition": "tile/text",
"attributes": {
"text": "Check-In",
"variant": "body",
"weight": "semibold"
}
},
{
"definition": "tile/text",
"attributes": {
"text": "{!$attrs.checkInTime}",
"variant": "body"
}
}
]
},
{
"definition": "tile/row",
"attributes": {
"gap": "sm"
},
"children": [
{
"definition": "tile/text",
"attributes": {
"text": "Check-Out",
"variant": "body",
"weight": "semibold"
}
},
{
"definition": "tile/text",
"attributes": {
"text": "{!$attrs.checkOutTime}",
"variant": "body"
}
}
]
},
{
"definition": "tile/row",
"attributes": {
"gap": "sm"
},
"children": [
{
"definition": "tile/text",
"attributes": {
"text": "Price / Night (USD)",
"variant": "body",
"weight": "semibold"
}
},
{
"definition": "tile/text",
"attributes": {
"text": "{!$attrs.pricePerNight}",
"variant": "body"
}
}
]
},
{
"definition": "tile/row",
"attributes": {
"gap": "sm"
},
"children": [
{
"definition": "tile/text",
"attributes": {
"text": "Rating",
"variant": "body",
"weight": "semibold"
}
},
{
"definition": "tile/text",
"attributes": {
"text": "{!$attrs.rating}",
"variant": "body"
}
}
]
}
]
}
]
}
]
}
]
}
}
}
```
**See Also**
- [Composition File](https://developer.salesforce.com/docs/platform/hxl/guide/hxl-widget-composition.md)
## Define Widget Configuration
The configuration file (`uiWidgets/hotelCard/hotelCard.uiwidget-meta.xml`) declares the widget bundle type required for deployment.
```xml
Hotel Card
Displays hotel details including name, city, check-in and check-out times, nightly price, and rating.
JSON
```
**See Also**
- [Widget Configuration File](https://developer.salesforce.com/docs/platform/hxl/guide/hxl-widget-configuration.md)
## Define the Lightning Type Schema
The custom Lightning type schema file (`lightningTypes/hotelInfo/schema.json`) defines the data structure. This schema establishes the properties available for mapping to your widget.
```json
{
"title": "Hotel Information",
"description": "Structured hotel data returned by the booking agent",
"lightning:type": "@apexClassType/c__HotelSearchResult$Hotel"
}
```
**See Also**
- [Core Concepts of Custom Lightning Types](https://developer.salesforce.com/docs/platform/lightning-types/guide/lightning-types-core.html)
## Map Lightning Type Data to the Widget
The renderer file (`lightningTypes/hotelInfo/renderer.json`) maps the Lightning type's data properties to the widget's attributes.
```json
{
"renderer": {
"componentOverrides": {
"$": {
"definition": "@widget/c/hotelCard",
"attributes": {
"hotelId": "{!$attrs.hotelId}",
"name": "{!$attrs.name}",
"city": "{!$attrs.city}",
"checkInTime": "{!$attrs.checkInTime}",
"checkOutTime": "{!$attrs.checkOutTime}",
"pricePerNight": "{!$attrs.pricePerNight}",
"rating": "{!$attrs.rating}"
}
}
}
}
}
```
**note:** For detailed information about widget references and attribute mapping, see [Connect Your Widget to a Custom Lightning Type](https://developer.salesforce.com/docs/platform/hxl/guide/hxl-rich-ui.md#connect-your-widget-to-a-custom-lightning-type).
**See Also**
- [Connect Your Widget to a Custom Lightning Type](https://developer.salesforce.com/docs/platform/hxl/guide/hxl-rich-ui.md#connect-your-widget-to-a-custom-lightning-type)
## Package Deployment Management
To deploy both the Lightning type and Widget together, include them in a single `package.xml` manifest.
This example shows a manifest that includes both the `hotelCard` widget and `hotelInfo` Lightning type.
```xml
hotelCard
UiWidgetBundle
hotelInfo
LightningTypeBundle
67.0
```
### Deployment Order
When you deploy a Lightning type that references a widget, deploy the widget first or include it in the same package. Metadata API resolves deployment ordering automatically within a single package.
If you deploy the components independently across separate deployments, maintain this sequential order:
1. Deploy the UiWidgetBundle package to your target org first.
2. Deploy the LightningTypeBundle package to your target org second.
## After Deployment
After you deploy the widget and the custom Lightning type, the widget is ready to render Agentforce action output in Lightning Experience.
**See Also**
- [Use HXL Widgets as Agentforce Action Output](https://developer.salesforce.com/docs/platform/hxl/guide/agentforce-action-output.md)
- [Core Concepts of Custom Lightning Types](https://developer.salesforce.com/docs/platform/lightning-types/guide/lightning-types-core.html)
- [Supported Applications and Platforms](https://developer.salesforce.com/docs/platform/hxl/guide/hxl-rich-ui.md#supported-applications-and-platforms)
- [HXL Components](https://developer.salesforce.com/docs/platform/reference/about-hxl-components.md#components)
# Example: Mapping a Hotel Card Widget for MCP
This example shows how output from a custom MCP server tool flows through two object-based custom Lightning types to the `hotelCard` widget in ChatGPT, Claude, or Slackbot.
This example uses three schema files that serve different purposes:
- The `hotelInfoResult` MCP result wrapper custom Lightning type schema describes the complete result returned by the MCP server tool, including `actionName`, `isSuccess`, and `outputValues`.
- The `hotelInfoOutputValues` MCP payload custom Lightning type schema describes the action-specific hotel data referenced by `outputValues`.
- The widget schema describes the UI shape, which is the attribute contract that defines the hotel information the card needs to render.
You map the nested data shape to the UI shape by using the `hotelInfoResult` custom Lightning type’s `renderer.json` file.
## Before You Begin
Download these sample data files.
- [hotelCardWidget.zip](https://resources.docs.salesforce.com/rel1/doc/en-us/static/misc/HotelCardWidget1.zip)
- [hotelInfoLightningType.zip](https://resources.docs.salesforce.com/rel1/doc/en-us/static/misc/HotelInfoLightningTypes1.zip)
- [hotelSearchResultApexClass.zip](https://resources.docs.salesforce.com/rel1/doc/en-us/static/misc/HotelSearchResultApexClassBundle1.zip)
## Project Directory Workspace Structure
This layout shows where the custom UiWidgetBundle and related LightningTypeBundle component files belong in your Salesforce DX project.
```
myProject/
force-app/
main/
default/
uiWidgets/
hotelCard/
hotelCard.json
hotelCard.uiwidget-meta.xml
schema.json
lightningTypes/
hotelInfoResult/
schema.json
renderer.json
hotelInfoOutputValues/
schema.json
```
**note:** In this directory structure, `renderer.json` sits directly parallel to `schema.json`. For widget references, create this file at the root level without using channel-specific subfolders. See [Connect Your Widget to a Custom Lightning Type](https://developer.salesforce.com/docs/platform/hxl/guide/hxl-rich-ui.md#connect-your-widget-to-a-custom-lightning-type).
**See Also**
- [UiWidgetBundle](https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_uiwidgetbundle.htm)
## Declare the Widget Attribute Contract
The widget schema file (`uiWidgets/hotelCard/schema.json`) defines the attributes that your widget accepts. These attributes become available as `{!$attrs.attributeName}` bindings in your widget's composition file and as mapping targets in the Lightning type's `renderer.json` file.
```json
{
"title": "Get Hotel Details Widget",
"description": "Displays hotel details including name, city, check-in and check-out times, nightly price, and rating.",
"type": "object",
"properties": {
"attributes": {
"lightning:type": "lightning__objectType",
"properties": {
"hotelId": {
"title": "Hotel ID",
"description": "Unique hotel identifier (e.g. HTL-101)",
"lightning:type": "lightning__textType"
},
"name": {
"title": "Name",
"description": "Hotel name",
"lightning:type": "lightning__textType"
},
"city": {
"title": "City",
"description": "City where the hotel is located",
"lightning:type": "lightning__textType"
},
"checkInTime": {
"title": "Check-In Time",
"description": "Standard check-in time",
"lightning:type": "lightning__textType"
},
"checkOutTime": {
"title": "Check-Out Time",
"description": "Standard check-out time",
"lightning:type": "lightning__textType"
},
"pricePerNight": {
"title": "Price Per Night",
"description": "Nightly price in USD",
"lightning:type": "lightning__numberType"
},
"rating": {
"title": "Rating",
"description": "Guest rating out of 5",
"lightning:type": "lightning__numberType"
}
}
}
}
}
```
**See Also**
- [Schema File](https://developer.salesforce.com/docs/platform/hxl/guide/hxl-widget-schema.md)
## Build the Widget Composition
The composition file (`uiWidgets/hotelCard/hotelCard.json`) defines the widget's visual structure and binds widget’s schema attributes to UI components by using `{!$attrs.attributeName}` expressions.
```json
{
"type": "lightning__agentforceWidget",
"contentBody": {
"widgetBody": {
"definition": "tile/widget",
"children": [
{
"definition": "tile/column",
"attributes": {
"gap": "md"
},
"children": [
{
"definition": "tile/container",
"children": [
{
"definition": "tile/text",
"attributes": {
"text": "{!$attrs.name}",
"variant": "h2"
}
},
{
"definition": "tile/row",
"attributes": {
"gap": "sm"
},
"children": [
{
"definition": "tile/text",
"attributes": {
"text": "{!$attrs.city}",
"variant": "caption",
"color": "muted"
}
},
{
"definition": "tile/text",
"attributes": {
"text": "•",
"variant": "caption",
"color": "muted"
}
},
{
"definition": "tile/text",
"attributes": {
"text": "{!$attrs.hotelId}",
"variant": "caption",
"color": "muted"
}
}
]
}
]
},
{
"definition": "tile/container",
"children": [
{
"definition": "tile/column",
"attributes": {
"gap": "sm"
},
"children": [
{
"definition": "tile/row",
"attributes": {
"gap": "sm"
},
"children": [
{
"definition": "tile/text",
"attributes": {
"text": "Check-In",
"variant": "body",
"weight": "semibold"
}
},
{
"definition": "tile/text",
"attributes": {
"text": "{!$attrs.checkInTime}",
"variant": "body"
}
}
]
},
{
"definition": "tile/row",
"attributes": {
"gap": "sm"
},
"children": [
{
"definition": "tile/text",
"attributes": {
"text": "Check-Out",
"variant": "body",
"weight": "semibold"
}
},
{
"definition": "tile/text",
"attributes": {
"text": "{!$attrs.checkOutTime}",
"variant": "body"
}
}
]
},
{
"definition": "tile/row",
"attributes": {
"gap": "sm"
},
"children": [
{
"definition": "tile/text",
"attributes": {
"text": "Price / Night (USD)",
"variant": "body",
"weight": "semibold"
}
},
{
"definition": "tile/text",
"attributes": {
"text": "{!$attrs.pricePerNight}",
"variant": "body"
}
}
]
},
{
"definition": "tile/row",
"attributes": {
"gap": "sm"
},
"children": [
{
"definition": "tile/text",
"attributes": {
"text": "Rating",
"variant": "body",
"weight": "semibold"
}
},
{
"definition": "tile/text",
"attributes": {
"text": "{!$attrs.rating}",
"variant": "body"
}
}
]
}
]
}
]
}
]
}
]
}
}
}
```
**See Also**
- [Composition File](https://developer.salesforce.com/docs/platform/hxl/guide/hxl-widget-composition.md)
## Define Widget Configuration
The configuration file (`uiWidgets/hotelCard/hotelCard.uiwidget-meta.xml`) declares the widget bundle type required for deployment.
```xml
Hotel Card
Displays hotel details including name, city, check-in and check-out times, nightly price, and rating.
JSON
```
**See Also**
- [Widget Configuration File](https://developer.salesforce.com/docs/platform/hxl/guide/hxl-widget-configuration.md)
## Define the Lightning Type Schema
Define two object-based custom Lightning type schemas for the MCP server tool output. The MCP result wrapper schema represents the complete tool result, and its `outputValues` property references the MCP payload schema that defines the action-specific output.
### Define the MCP Payload Custom Lightning Type
The custom Lightning type schema file (`lightningTypes/hotelInfoOutputValues/schema.json`) defines the hotel-information payload referenced by the result wrapper’s `outputValues` property. Its `hotelInfo` property references the `HotelSearchResult.Hotel` Apex class.
```json
{
"title": "Hotel Info Output Values",
"description": "Payload fields from the HotelSearchResult response",
"type": "object",
"lightning:type": "lightning__objectType",
"unevaluatedProperties": false,
"lightning:tags": ["mcp"],
"properties": {
"hotelInfo": {
"title": "Hotel Info",
"lightning:type": "@apexClassType/c__HotelSearchResult$Hotel"
}
}
}
```
### Define the MCP Result Wrapper Custom Lightning Type
The custom Lightning type schema file (`lightningTypes/hotelInfoResult/schema.json`) represents the complete MCP server tool result. Its `outputValues` property references the `hotelInfoOutputValues` MCP payload custom Lightning type.
```json
{
"title": "Hotel Info Result",
"description": "Invocable-action result envelope for the HotelSearchResult MCP tool",
"type": "object",
"lightning:type": "lightning__objectType",
"unevaluatedProperties": false,
"lightning:tags": ["mcp"],
"properties": {
"actionName": {
"title": "Action Name",
"lightning:type": "lightning__textType"
},
"isSuccess": {
"title": "Is Success",
"lightning:type": "lightning__booleanType"
},
"outputValues": {
"title": "Output Values",
"lightning:type": "c__hotelInfoOutputValues"
}
}
}
```
**See Also**
- [Core Concepts of Custom Lightning Types](https://developer.salesforce.com/docs/platform/lightning-types/guide/lightning-types-core.html)
## Map Lightning Type Data to the Widget
The `renderer.json` file (`lightningTypes/hotelInfoResult/renderer.json`) maps nested hotel properties under `outputValues` to attributes defined in the `hotelCard` widget’s `schema.json` file.
```json
{
"renderer": {
"componentOverrides": {
"$": {
"definition": "@widget/c/hotelCard",
"attributes": {
"hotelId": "{!$attrs.outputValues.hotelInfo.hotelId}",
"name": "{!$attrs.outputValues.hotelInfo.name}",
"city": "{!$attrs.outputValues.hotelInfo.city}",
"checkInTime": "{!$attrs.outputValues.hotelInfo.checkInTime}",
"checkOutTime": "{!$attrs.outputValues.hotelInfo.checkOutTime}",
"pricePerNight": "{!$attrs.outputValues.hotelInfo.pricePerNight}",
"rating": "{!$attrs.outputValues.hotelInfo.rating}"
}
}
}
}
}
```
**note:** For detailed information about widget references and attribute mapping, see [Connect Your Widget to a Custom Lightning Type](https://developer.salesforce.com/docs/platform/hxl/guide/hxl-rich-ui.md#connect-your-widget-to-a-custom-lightning-type).
**See Also**
- [Connect Your Widget to a Custom Lightning Type](https://developer.salesforce.com/docs/platform/hxl/guide/hxl-rich-ui.md#connect-your-widget-to-a-custom-lightning-type)
## Package Deployment Management
To deploy the widget and both custom Lightning types together, include them in a single `package.xml` manifest.
This manifest includes the `hotelCard` widget, the `hotelInfoOutputValues` MCP payload custom Lightning type, and the `hotelInfoResult` MCP result wrapper custom Lightning type.
```xml
hotelCard
UiWidgetBundle
hotelInfoOutputValues
hotelInfoResult
LightningTypeBundle
67.0
```
### Deployment Order
When you deploy a Lightning type that references a widget, deploy the widget first or include it in the same package. Metadata API resolves deployment ordering automatically within a single package.
If you deploy the components independently across separate deployments, maintain this sequential order:
1. Deploy the UiWidgetBundle package to your target org first.
2. Deploy the LightningTypeBundle package to your target org second.
## After Deployment
After you deploy the widget and both custom Lightning types, the widget is ready to render MCP server tool output in ChatGPT, Claude, or Slackbot.
**See Also**
- [Use HXL Widgets on MCP Channels](https://developer.salesforce.com/docs/platform/hxl/guide/hxl-mcp-channels.md)
- [Core Concepts of Custom Lightning Types](https://developer.salesforce.com/docs/platform/lightning-types/guide/lightning-types-core.html)
- [Supported Applications and Platforms](https://developer.salesforce.com/docs/platform/hxl/guide/hxl-rich-ui.md#supported-applications-and-platforms)
- [HXL Components](https://developer.salesforce.com/docs/platform/reference/about-hxl-components.md#components)
# Explore Widgets in HXL Playground
HXL Playground ([https://www.headlessexperiencelayer.com](https://www.headlessexperiencelayer.com)) is an interactive, browser-based tool for learning and building with the Headless Experience Layer (HXL). Describe your UI as declarative JSON, and the playground renders the UI natively across multiple surfaces.
- **[Components](https://developer.salesforce.com/docs/platform/hxl/guide/playground-components.md)**: Learn about HXL components and their properties.
- **[Widgets](https://developer.salesforce.com/docs/platform/hxl/guide/playground-widgets.md)**: Compose components into complete, reusable UI.
- **[Tutorials](https://www.headlessexperiencelayer.com/#01-hello-world)**: Learn HXL concepts step by step, from a single text block to a full widget.
Use the playground's top navigation bar to switch pages. To change the theme, select light, dark, or system mode at the top of any page.

## Next Steps
- Browse the [components reference](/docs/platform/hxl/references/hxl-reference-about/) for the properties and behavior of each component.
- Work through the [Tutorials](https://www.headlessexperiencelayer.com/#01-hello-world) to learn HXL concepts.
- Compose your own widget on the [Widgets](https://www.headlessexperiencelayer.com/#widget/local) page and preview it across surfaces.
# Get Started with Headless Experience Layer
Headless Experience Layer (HXL) is a unified experience engine and platform designed to deliver consistent, portable, and rich user experiences across various surfaces. HXL is a UI technology-agnostic platform that enables developers to “write once and run anywhere.”

Use HXL to build widgets for interactive and rich content, such as a dashboard that summarizes your data or a table with action buttons. Build a widget once and deploy it to Agentforce, ChatGPT, Claude, and Slackbot. By using HXL widgets, agent responses and conversational UI can render natively on any target surface without requiring developers to rebuild features for each channel.
## Key HXL Advantages
- **Operational agility:** Build logic once; deploy to any surface using the same HXL widgets. Widgets provide interactive and reusable UI blocks that decouple your business logic from presentation.
- **Deterministic governance:** Ground all AI interactions in the same metadata and follow the same deterministic business rules via centrally managed AI guardrails no matter where they occur.
- **Reduced integration tax:** Define every interaction with Custom Lightning Types, eliminating the need for custom API bridges between your Salesforce org and external UI surfaces.
- **Inherited security:** Every experience automatically inherits Salesforce’s native permissions and sharing models ensuring secure interactions.
## Build Rich UI with HXL Widgets
To get started, review the [prerequisites](https://developer.salesforce.com/docs/platform/hxl/guide/prerequisites.md). Set up your development environment and enable HXL in your org.
Then, learn about HXL components and build widgets in the [HXL Playground](https://www.headlessexperiencelayer.com/playground/). Experiment with mock data, refine your custom code, and copy the resulting widget definitions to use in your agentic HXL app.
Alternatively, speed up development by vibe coding widgets with [Agentforce Vibes](https://developer.salesforce.com/docs/platform/agentforcevibes/guide/afv-get-started.html).
# Headless Experience Layer Release Notes
To learn about the most recent updates and changes to Headless Experience Layer (HXL), see the [Salesforce Release Notes](https://help.salesforce.com/s/articleView?id=release-notes.rn_headless360.htm&release=262).
**See Also**
- [Salesforce Dev Blog: What Salesforce Headless 360 Means For Developers](https://developer.salesforce.com/blogs/2026/05/headless-360-what-it-means-for-developers)
# HXL Components
The [Components](https://www.headlessexperiencelayer.com/#components) page is an interactive catalog of available HXL components. Inspect a component's configuration and see how it renders across each channel. To facilitate UI development, copy and paste the JSON in your widget bundle's `.json` composition file.
## Browse the Components
The left sidebar lists all available components, grouped by category. Expand or collapse each category to show or hide its components. Each category shows a component count. A search box at the top of the sidebar filters components by name.
Every component displays a release status badge next to its name.
- **Beta** components are available and stable for evaluation.
- **Developer (Dev) Preview** components are for early access, and their APIs can still change. If you use dev preview components, we recommend that you use them in a sandbox org.

## Inspect and Preview a Component
To load a component in the workspace, select the component from the sidebar.
- The editor panel shows the component's configuration as declarative JSON. When you edit the component's configuration, the preview refreshes automatically.
- The preview panel shows a live rendering of the component. Use the preview toggle at the top of the preview pane to see how the same component definition renders natively in Agentforce, Slackbot, and more.
For the full property reference for each component, see the [HXL Components Reference](https://developer.salesforce.com/docs/platform/hxl/references/).
## Review Common Component Patterns
Each component page includes examples that show common composition patterns. Explore the available variants and sizes to understand how they render on a surface. To speed up development and ensure consistency, reuse the patterns in your widget bundles.
# HXL Components
Headless Experience Layer (HXL) components are the building blocks that you compose into experiences. Each component defines a single piece of content or layout structure that you can combine. HXL renders each component natively on each supported channel.
**note:** For the beta release, HXL components are supported for Agentforce, ChatGPT, Claude, and Slackbot.
The HXL component reference lists UI components you can use to build widgets. Use the reference to find the right component for your content, layout, or interaction. Review a component's page for its properties, known limitations, and usage examples.
For additional components that are in developer preview, see the [HXL Playground](https://www.headlessexperiencelayer.com/?tab=docs#components/). Developer preview components are for early access, and their APIs can still change. If you use developer preview components, we recommend that you use them in a sandbox org.
- [**Accordion**](https://developer.salesforce.com/docs/platform/hxl/references/hxl-reference-about/components/accordion.md) (`tile/accordion`)
Organizes content into vertically stacked, expandable sections. Each section has a header and nested content.
- [**Accordion Item**](https://developer.salesforce.com/docs/platform/hxl/references/hxl-reference-about/components/accordionItem.md) (`tile/accordionItem`)
Creates an individual expandable section within an accordion. Each section includes a clickable header with a title and optional icon.
- [**Avatar**](https://developer.salesforce.com/docs/platform/hxl/references/hxl-reference-about/components/avatar.md) (`tile/avatar`)
Identifies a user, entity, or object visually. An avatar contains the image URL, text initials, icon identifier, alternative text, shape, and size.
- [**Badge**](https://developer.salesforce.com/docs/platform/hxl/references/hxl-reference-about/components/badge.md) (`tile/badge`)
Presents a small inline indicator for categorization or status.
- [**Button**](https://developer.salesforce.com/docs/platform/hxl/references/hxl-reference-about/components/button.md) (`tile/button`)
Shows a clickable element that triggers an action. A button includes semantic and visual variants, optional icon decoration, and the loading state.
- [**Callout**](https://developer.salesforce.com/docs/platform/hxl/references/hxl-reference-about/components/callout.md) (`tile/callout`)
Highlights a content block for emphasis. The callout wraps child content with a semantic variant, optional title, and description.
- [**Code**](https://developer.salesforce.com/docs/platform/hxl/references/hxl-reference-about/components/code.md) (`tile/code`)
Shows preformatted source code content with an optional language label.
- [**Column**](https://developer.salesforce.com/docs/platform/hxl/references/hxl-reference-about/components/column.md) (`tile/column`)
Shows children components in a vertical container with a configurable gap, cross-axis alignment, and width.
- [**Container**](https://developer.salesforce.com/docs/platform/hxl/references/hxl-reference-about/components/container.md) (`tile/container`)
Creates a container with a rounded border that accepts any children.
- [**Icon**](https://developer.salesforce.com/docs/platform/hxl/references/hxl-reference-about/components/icon.md) (`tile/icon`)
Shows a standalone icon.
- [**Image**](https://developer.salesforce.com/docs/platform/hxl/references/hxl-reference-about/components/image.md) (`tile/image`)
Shows an image based on a source URL, a required alternative text for accessibility, and an optional size proxy.
- [**Link**](https://developer.salesforce.com/docs/platform/hxl/references/hxl-reference-about/components/link.md) (`tile/link`)
Shows a text-based hyperlink with a destination URL. Configure the visual style as needed.
- [**List**](https://developer.salesforce.com/docs/platform/hxl/references/hxl-reference-about/components/list.md) (`tile/list`)
Lists a series of related items in a column. Use the `tile/listitem` child component for a list item.
- [**List Item**](https://developer.salesforce.com/docs/platform/hxl/references/hxl-reference-about/components/listItem.md) (`tile/listItem`)
Adds a single row inside a list. Use these children components: `tile/text`, `tile/link`, or `tile/icon`.
- [**Markdown**](https://developer.salesforce.com/docs/platform/hxl/references/hxl-reference-about/components/markdown.md) (`tile/markdown`)
Shows markdown-formatted text content. Use headings, lists, links, images, code blocks, tables, and standard inline formatting.
- [**Progress**](https://developer.salesforce.com/docs/platform/hxl/references/hxl-reference-about/components/progress.md) (`tile/progress`)
Indicates the task completion percentage visually, which can be presented as a linear bar or circular ring shape.
- [**Row**](https://developer.salesforce.com/docs/platform/hxl/references/hxl-reference-about/components/row.md) (`tile/row`)
Shows children components in a horizontal container with a configurable gap, alignment, justification, and wrapping.
* [**Separator**](https://developer.salesforce.com/docs/platform/hxl/references/hxl-reference-about/components/separator.md) (`tile/separator`)
Adds a visual boundary between content sections by using a horizontal or vertical line.
* [**Spacer**](https://developer.salesforce.com/docs/platform/hxl/references/hxl-reference-about/components/spacer.md) (`tile/spacer`)
Adds an empty layout element that creates explicit space or flexible fill between sibling components.
* [**Spinner**](https://developer.salesforce.com/docs/platform/hxl/references/hxl-reference-about/components/spinner.md) (`tile/spinner`)
Shows an indeterminate circular loading indicator. Configure the accessible label and an optional size setting on the spinner.
* [**Table**](https://developer.salesforce.com/docs/platform/hxl/references/hxl-reference-about/components/table.md) (`tile/table`)
Shows tabular data with column definitions and row data. Columns define the structure, and rows are key-value objects that map column keys to cell values.
* [**Text**](https://developer.salesforce.com/docs/platform/hxl/references/hxl-reference-about/components/text.md) (`tile/text`)
Shows text content with optional typography styling. Configure the appearance by using variant, weight, color, italic, and strikethrough settings.
## See Also
- [HXL Lightning Types Reference](https://developer.salesforce.com/docs/platform/hxl/references/hxl-reference-about/hxl-lightning-types.md)
- [HXL Playground](ttps://www.headlessexperiencelayer.com/)
# HXL Lightning Types Reference
Headless Experience Layer (HXL) components use Lightning types in their property definitions. Each type defines the shape and allowed values of a property. The types describe layout, formatting, and structured data for HXL components. HXL renders each type natively on supported surfaces.
For input-focused Lightning types, see the [Lightning Types Reference](https://developer.salesforce.com/docs/platform/lightning-types/references/lightning-types/lightning-types-reference.html) instead.
HXL Lightning types include:
- [Layout and sizing types](#layout-and-sizing-types)
- [Content and display types](#content-and-display-types)
- [Interaction types](#interaction-types)
- [Table types](#table-types)
---
## Layout and Sizing Types
Control how components are sized, spaced, aligned, and positioned within their containers.
### lightning\_\_alignmentType
Use the `lightning__alignmentType` type to control the cross-axis alignment of a container's children. The type is a string enumeration.
**For Use In**
Agentforce, ChatGPT, Claude, Slackbot
The `lightning__alignmentType` type accepts these values. The default is `stretch`.
| Value | Description |
| ------------------- | ----------------------------------------------- |
| `start` | Aligns children to the start of the cross axis. |
| `center` | Centers children on the cross axis. |
| `end` | Aligns children to the end of the cross axis. |
| `stretch` (default) | Stretches children to fill the cross axis. |
### lightning\_\_extentType
Use the `lightning__extentType` type to specify how much space a block occupies within its container. The type is a string enumeration.
**For Use In**
Agentforce, ChatGPT, Claude, Slackbot
The `lightning__extentType` type accepts these values. The default is `auto`.
| Value | Description |
| ---------------- | -------------------------------------- |
| `auto` (default) | Sizes the block to fit its content. |
| `xs` | Extra small extent. |
| `sm` | Small extent. |
| `md` | Medium extent. |
| `lg` | Large extent. |
| `xl` | Extra large extent. |
| `full` | Occupies the full available extent. |
| `stretch` | Stretches to fill the available space. |
### lightning\_\_gapType
Use the `lightning__gapType` type to control the space between child elements in a container. The type is a string enumeration.
**For Use In**
Agentforce, ChatGPT, Claude, Slackbot
The `lightning__gapType` type accepts these values. The default is `md`.
| Value | Description |
| -------------- | -------------------------- |
| `none` | No space between children. |
| `xs` | Extra small gap. |
| `sm` | Small gap. |
| `md` (default) | Medium gap. |
| `lg` | Large gap. |
| `xl` | Extra large gap. |
### lightning\_\_sizeType
Use the `lightning__sizeType` type to specify the size of a block on a shared t-shirt-size scale. The type is a string enumeration.
**For Use In**
Agentforce, ChatGPT, Claude, Slackbot
The `lightning__sizeType` type accepts these values. The default is `md`.
| Value | Description |
| -------------- | ----------------- |
| `xs` | Extra small size. |
| `sm` | Small size. |
| `md` (default) | Medium size. |
| `lg` | Large size. |
| `xl` | Extra large size. |
### lightning\_\_orientationType
Use the `lightning__orientationType` type to set the layout orientation of a component. The type is a string enumeration.
**For Use In**
Agentforce, ChatGPT, Claude, Slackbot
The `lightning__orientationType` type accepts these values. The default is `horizontal`.
| Value | Description |
| ---------------------- | ------------------------------ |
| `horizontal` (default) | Lays out content horizontally. |
| `vertical` | Lays out content vertically. |
### lightning\_\_justifyType
Use the `lightning__justifyType` type to control the horizontal distribution of children within a container. The type is a string enumeration.
**For Use In**
Agentforce, ChatGPT, Claude, Slackbot
The `lightning__justifyType` type accepts these values. The default is `start`.
| Value | Description |
| ----------------- | ------------------------------------------------------------------------------------------------ |
| `start` (default) | Packs children toward the start. |
| `center` | Centers children along the main axis. |
| `end` | Packs children toward the end. |
| `between` | Distributes children with equal space between them. |
| `around` | Distributes children with equal space around each. |
| `evenly` | Distributes children so that spacing between any two adjacent items, and to the edges, is equal. |
| `space-between` | Alias for `between`. |
| `space-around` | Alias for `around`. |
| `space-evenly` | Alias for `evenly`. |
### lightning\_\_positionType
Use the `lightning__positionType` type to specify a preferred position, such as the placement of a tooltip relative to its anchor. The type is a string enumeration.
**For Use In**
Agentforce, ChatGPT, Claude, Slackbot
The `lightning__positionType` type accepts these values. The default is `top`.
| Value | Description |
| --------------- | ------------------------------------- |
| `top` (default) | Positions above the anchor. |
| `right` | Positions to the right of the anchor. |
| `bottom` | Positions below the anchor. |
| `left` | Positions to the left of the anchor. |
---
## Content and Display Types
Format text, icons, and status indicators shown to users.
### lightning\_\_iconName
Use the `lightning__iconName` type to specify a semantic icon identifier. Renderers map this identifier to a concrete icon in their own icon system. The type is a string enumeration.
**For Use In**
Agentforce, ChatGPT, Claude, Slackbot
The `lightning__iconName` type accepts these values.
| | | | |
| -------------------------------- | --------------- | ---------------- | ------------------------------ |
| `activity` | `alert-circle` | `alert-triangle` | `align-center` |
| `align-horizontal-space-between` | `align-left` | `align-right` | `align-vertical-space-between` |
| `bell` | `bookmark` | `box` | `braces` |
| `briefcase` | `building` | `calculator` | `calendar` |
| `caret-down` | `caret-left` | `caret-right` | `caret-up` |
| `check` | `check-circle` | `chevron-down` | _`chevron-left`_ |
| `chevron-right` | `chevron-up` | `circle` | `circle-dot` |
| `clock` | `cloud` | `code` | `component` |
| `copy` | `credit-card` | `crown` | `database` |
| `dashboard` | `divide` | `dollar-sign` | `dot` |
| `download` | `edit` | `equal` | `equal-not` |
| `eye` | `eye-off` | `file` | `file-edit` |
| `file-text` | `filter` | `folder` | `gauge` |
| `git-branch` | `git-compare` | `globe` | `grid` |
| `hash` | `headset` | `heart` | `help-circle` |
| `home` | `image` | `inbox` | `info` |
| `layers` | `layout` | `lightbulb` | `lightning` |
| `link` | `list` | `list-checks` | `list-checks-rtl` |
| `loader` | `lock` | `mail` | `map` |
| `map-pin` | `maximize` | `megaphone` | `message` |
| `microphone` | `minus` | `minus-circle` | `mouse-pointer-click` |
| `open-in-new` | `package` | `palette` | `pencil` |
| `phone` | `plane` | `plus` | `plus-circle` |
| `plug` | `refresh` | `repeat` | `rotate-ccw` |
| `rotate-cw` | `search` | `send` | `server` |
| `settings` | `share` | `shield` | `shield-alert` |
| `shield-check` | `shopping-cart` | `space` | `square` |
| `square-dashed` | `star` | `sticky-note` | `table` |
| `tag` | `target` | `television` | `thumb-down` |
| `thumb-up` | `ticket` | `toggle-left` | `trash` |
| `trending-up` | `upload` | `user` | `user-circle` |
| `users` | `video` | `wifi` | `x` |
| `x-circle` | | | |
For available icons, see the [HXL Playground Editor](https://www.headlessexperiencelayer.com/playground/?renderer=acc&theme=slack#components/icon/all-icons).
### lightning\_\_markdownTextType
Use the `lightning__markdownTextType` type for text content formatted as Markdown. The type corresponds to the string type in a JSON schema.
**For Use In**
Agentforce, ChatGPT, Claude, Slackbot
The `lightning__markdownTextType` type supports these configurable keywords.
| Keyword | Required | Type | Description |
| ------------- | -------- | ------ | ----------------------------------------------- |
| `title` | Yes | String | The label text for the field |
| `description` | No | String | The help text that describes the expected input |
### lightning\_\_textalignType
Use the `lightning__textalignType` type to control the horizontal alignment of text content. The type is a string enumeration.
**For Use In**
Agentforce, ChatGPT, Claude, Slackbot
The `lightning__textalignType` type accepts these values. The default is `left`.
| Value | Description |
| ---------------- | ------------------------- |
| `left` (default) | Aligns text to the left. |
| `center` | Centers text. |
| `right` | Aligns text to the right. |
### lightning\_\_severityType
Use the `lightning__severityType` type to indicate an alert type or severity level. The type is a string enumeration.
**For Use In**
Agentforce, ChatGPT, Claude, Slackbot
The `lightning__severityType` type accepts these values. The default is `info`.
| Value | Description |
| ---------------- | -------------------------------- |
| `info` (default) | Informational severity. |
| `success` | Positive or successful severity. |
| `warning` | Cautionary or advisory severity. |
| `error` | Urgent or critical severity. |
---
## Interaction Types
Describe the events dispatched when a user interacts with a component.
### lightning\_\_actionType
Use the `lightning__actionType` type to describe an action performed when a user interacts with a component. Because `lightning__actionType` is a complex type, its value is represented as an object.
This table shows the properties of the object that the `lightning__actionType` type describes.
| Property | Required or Optional | Type | Description |
| ------------ | -------------------- | --------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `definition` | Required | `lightning__textType` | The action identifier. Valid values include [`action/openLink`](#actionopenlink) and [`action/sendMessage`](#actionsendmessage), each with its own attributes. |
| `attributes` | Required | Object | Action-specific payload. A predefined action carries its typed payload here; a local action an arbitrary bag. |
**For Use In**
Agentforce, ChatGPT, Claude, Slackbot
HXL provides these predefined actions. Each is identified by its `definition` value and takes a specific set of `attributes`.
#### action/openLink
The `action/openLink` action opens a URL in the browser. It executes synchronously to preserve the user gesture context that the browser requires to open a window.
The `action/openLink` action takes these attributes.
| Attribute | Required or Optional | Type | Description |
| --------- | -------------------- | ------ | ---------------- |
| `url` | Required | String | The URL to open. |
This example shows a button that opens a link when clicked.
```json
{
"definition": "tile/button",
"attributes": {
"label": "Open Link",
"variant": "primary",
"actions": {
"click": [
{
"definition": "action/openLink",
"attributes": {
"url": "https://www.example.com"
}
}
]
}
}
}
```
#### action/sendMessage
The `action/sendMessage` action sends a message to the host or agent. The message goes directly to the agent rather than being displayed to the user. The agent processes it like a user message and responds with results. The agent may ask for confirmation before executing risky actions.
The `action/sendMessage` action takes these attributes.
| Attribute | Required or Optional | Type | Description |
| --------- | -------------------- | ------ | ------------------------- |
| `content` | Required | String | The message text to send. |
This example shows a button that sends a message when clicked.
```json
{
"definition": "tile/button",
"attributes": {
"label": "Yes, proceed",
"actions": {
"click": [
{
"definition": "action/sendMessage",
"attributes": {
"content": "Yes, proceed with the update"
}
}
]
}
}
}
```
### lightning\_\_eventType
Use the `lightning__eventType` type to describe an event dispatched when a user interacts with a tile. Because `lightning__eventType` is a complex type, its value is represented as an object.
This table shows the properties of the object that the `lightning__eventType` type describes.
| Property | Required or Optional | Type | Description |
| ------------ | -------------------- | --------------------- | -------------------------------------------------------------------- |
| `definition` | Required | `lightning__textType` | Action identifier. Maximum 255 characters. |
| `attributes` | Optional | Object | Event-specific attributes. The object accepts additional properties. |
**For Use In**
Agentforce, ChatGPT, Claude, Slackbot
This example shows an event with a definition and event-specific attributes.
```json
{
"definition": "myAction",
"attributes": {
"recordId": "001XXXXXXXXXXXXXXX"
}
}
```
---
## Table Types
Structure the columns and cell values rendered by the table component.
The table types define how the `tile/table` component structures its columns and cells. Each column type is a discriminated object identified by its `type` property.
### lightning\_\_cellValueType
Use the `lightning__cellValueType` type to represent a single table cell value. A cell holds exactly one value at a time — a string or a number, but never both.
**For Use In**
Agentforce, ChatGPT, Claude, Slackbot
The `lightning__cellValueType` type accepts one of these value types.
| Type | Description |
| ------ | ----------------------------------- |
| String | Short text — up to 255 characters. |
| Number | Numeric value — integer or decimal. |
### lightning\_\_dateColumnType
Use the `lightning__dateColumnType` type to format table cell values as localized dates or datetimes. The type accepts ISO 8601 strings (for example, `2024-01-15T14:30:00Z` or `2024-01-15`) and numeric Unix timestamps in milliseconds (for example, `1705312200000`). Non-parseable cell values fall back to plain text display.
**For Use In**
Agentforce, ChatGPT, Claude, Slackbot
Because `lightning__dateColumnType` is a complex type, its value is represented as an object.
This table shows the properties of the object that the `lightning__dateColumnType` type describes.
| Property | Required or Optional | Type | Description |
| ----------- | -------------------- | ------ | ------------------------------------------------------------------------------------------------------------------------------- |
| `type` | Required | String | Discriminator field. Always the string `date`. |
| `format` | Optional | String | The date format to show. `date` (default) shows only the date; `datetime` shows both date and time. |
| `dateStyle` | Optional | String | Date formatting verbosity: `full`, `long`, `medium`, or `short`. Defaults to `short`. |
| `timeStyle` | Optional | String | Time formatting verbosity: `full`, `long`, `medium`, or `short`. Applies only when `format` is `datetime`. Defaults to `short`. |
This example shows a date column that displays both date and time.
```json
{
"type": "date",
"format": "datetime",
"dateStyle": "medium",
"timeStyle": "short"
}
```
### lightning\_\_numberColumnType
Use the `lightning__numberColumnType` type to format numeric table cell values with locale-aware decimal, percent, or currency formatting. Row values must be raw numeric strings,for example, `1234.56` or `0.75`. The renderer handles all formatting. Non-numeric cell values fall back to plain text display.
**For Use In**
Agentforce, ChatGPT, Claude, Slackbot
Because `lightning__numberColumnType` is a complex type, its value is represented as an object.
This table shows the properties of the object that the `lightning__numberColumnType` type describes.
| Property | Required or Optional | Type | Description |
| ----------------------- | -------------------- | ------------------------ | ---------------------------------------------------------------------------------------------------------------------------------- |
| `type` | Required | String | Discriminator field. Always the string `number`. |
| `format` | Optional | String | Number formatting style: `decimal` (default), `percent`, or `currency`. |
| `currencyCode` | Optional | String | ISO 4217 currency code (for example, `USD` or `EUR`). Used only when `format` is `currency`. Defaults to `USD`. |
| `currencyCodeKey` | Optional | String | Row field key that supplies a per-row ISO 4217 currency code. Used only when `format` is `currency`. Falls back to `currencyCode`. |
| `currencyDisplayAs` | Optional | String | How the currency is displayed: `symbol`, `narrowSymbol`, `code`, or `name`. Used only when `format` is `currency`. |
| `minimumFractionDigits` | Optional | `lightning__integerType` | Minimum number of decimal places to display. An integer between 0 and 20. |
| `maximumFractionDigits` | Optional | `lightning__integerType` | Maximum number of decimal places to display. An integer between 0 and 20. |
This example shows a currency column formatted in euros.
```json
{
"type": "number",
"format": "currency",
"currencyCode": "EUR",
"currencyDisplayAs": "symbol",
"minimumFractionDigits": 2,
"maximumFractionDigits": 2
}
```
### lightning\_\_linkColumnType
Use the `lightning__linkColumnType` type to render table cell values as clickable hyperlinks. When applied to a column, cell values become anchor elements.
**For Use In**
Agentforce, ChatGPT, Claude, Slackbot
Because `lightning__linkColumnType` is a complex type, its value is represented as an object.
This table shows the properties of the object that the `lightning__linkColumnType` type describes.
| Property | Required or Optional | Type | Description |
| -------- | -------------------- | ------ | ------------------------------------------------------------------------------------------------------------------ |
| `type` | Required | String | Discriminator field. Always the string `link`. |
| `urlKey` | Optional | String | Row field key containing the URL. When omitted, the column key value is used as both the display text and the URL. |
This example shows a link column that displays a person's name and links to a separate profile URL.
```json
{
"type": "link",
"urlKey": "profileUrl"
}
```
### lightning\_\_picklistColumnType
Use the `lightning__picklistColumnType` type to render table cell values by resolving row data values to human-readable labels from a defined set of options. Each cell value in row data is a canonical value string that maps to a label from the options array. The table displays the label. When a row value doesn't match any option, the raw value is displayed as a fallback.
**For Use In**
Agentforce, ChatGPT, Claude, Slackbot
Because `lightning__picklistColumnType` is a complex type, its value is represented as an object.
This table shows the properties of the object that the `lightning__picklistColumnType` type describes.
| Property | Required or Optional | Type | Description |
| --------- | -------------------- | ---------------------------------------- | ------------------------------------------------------------- |
| `type` | Required | String | Discriminator field. Always the string `picklist`. |
| `options` | Required | Array of `lightning__picklistOptionType` | Available picklist choices. Must contain at least one option. |
This example shows a picklist column that maps status values to labels.
```json
{
"type": "picklist",
"options": [
{ "label": "Active", "value": "active" },
{ "label": "Inactive", "value": "inactive" }
]
}
```
### lightning\_\_picklistOptionType
Use the `lightning__picklistOptionType` type to define a single picklist option with a display label and a canonical data value. This type is the item type in a picklist column's `options` array. Separating the label from the value supports localization (labels change per locale, values stay constant) and programmatic operations such as filtering and sorting.
**For Use In**
Agentforce, ChatGPT, Claude, Slackbot
Because `lightning__picklistOptionType` is a complex type, its value is represented as an object.
This table shows the properties of the object that the `lightning__picklistOptionType` type describes.
| Property | Required or Optional | Type | Description |
| -------- | -------------------- | --------------------- | -------------------------------------------------------------------------------------------------------------------- |
| `label` | Required | `lightning__textType` | Human-readable display text for this option. Maximum 255 characters. |
| `value` | Required | `lightning__textType` | Canonical value stored in row data for this option. Must be unique within the options array. Maximum 255 characters. |
This example shows a single picklist option.
```json
{
"label": "In Progress",
"value": "in_progress"
}
```
# Icon
**`tile/icon`**
Shows a standalone icon.
## Properties
| Name | Required | Lightning Type | Default | Description |
| ---- | -------- | -------------- | ------- | ----------- |
| alt | No | `lightning__textType` | | An alternative text that describes what the icon conveys, for accessibility. Recommended to be concise (under 125 characters); an empty string (the default) marks the icon as decorative and hides it from screen readers. |
| color | No | `lightning__textType` | `default` | The color of the icon. Valid values include `default`, `error`, `muted`, `primary`, `success`, and `warning`. |
| name | Yes | `lightning__iconName` | | A semantic icon identifier specifying which icon symbol to show. |
| size | No | `lightning__textType` | `md` | The size of the icon. Valid values include `xs` for extra small, `sm` for small, `md` for medium (default), `lg` for large, and `xl` for extra large. |
## Usage
Use an icon to show a standalone symbol that conveys meaning instantly, such as with a status indicator, a visual cue next to a label, or a lightweight decorative mark. Set `name` to choose the symbol, and use `size` and `color` to fit it to its context.
```json
{
"definition": "tile/icon",
"attributes": { "name": "check-circle", "color": "success" }
}
```
To label an icon, place both in a [`tile/row`](https://developer.salesforce.com/docs/platform/hxl/references/hxl-reference-about/row.md) and align them on the center axis.
```json
{
"definition": "tile/row",
"attributes": { "gap": "sm", "align": "center" },
"children": [
{
"definition": "tile/icon",
"attributes": { "name": "alert-triangle", "color": "warning" }
},
{
"definition": "tile/text",
"attributes": { "text": "Your trial ends in 3 days." }
}
]
}
```
For available icons, see the [HXL Playground Editor](https://www.headlessexperiencelayer.com/playground/?renderer=acc&theme=slack#components/icon/all-icons).
## Size
Use these `size` values to control the icon size.
- `xs`: Extra small icons for dense inline contexts where the icon accompanies small text.
- `sm`: Small icons for compact rows and secondary cues.
- `md` (default): Medium icons for most standalone and labeled uses.
- `lg`: Large icons for emphasis or when the icon is a focal point.
- `xl`: Extra large icons for hero-style or feature callouts where the icon leads.
## Color
Use these `color` values to convey status or match the icon to its surrounding context.
- `default` (default): Neutral foreground color for decorative or non-status icons.
- `error`: Signals a failure or destructive state, such as a validation error.
- `muted`: Subdued, low-emphasis color for secondary or supporting cues.
- `primary`: The brand accent color to highlight a key icon.
- `success`: Signals a positive or completed state, such as a confirmation.
- `warning`: Signals caution or a state that requires attention.
## Design Guidelines
Consider these guidelines when working with icons.
- Match `color` to meaning — use `success`, `warning`, and `error` for status and reserve `default` or `muted` for decorative marks.
- Pair an icon with a `tile/text` label when the symbol alone can be ambiguous. Wrap both in a `tile/row`.
- Keep `size` consistent with neighboring text so the icon aligns to the line rather than towering over it.
- To make an icon trigger an action, attach the base `action` attribute instead of using a `tile/button`.
- On surfaces with a limited icon set, choose common, well-known `name` values so they don't fall back to a generic symbol.
## Limitations
Note any limitations that apply to this component.
### Slackbot
No known limitations for `tile/icon` in Slackbot.
### ChatGPT
No known limitations for `tile/icon` in ChatGPT.
### Agentforce
No known limitations for `tile/icon` in Agentforce. `name` maps to an SLDS styled icon.
## See Also
- [HXL Lightning Types Reference](https://developer.salesforce.com/docs/platform/hxl/references/hxl-lightning-types.md)
- [_HXL Playground_: Icon](https://www.headlessexperiencelayer.com/#components/icon)
# Image
**`tile/image`**
Shows an image from a source URL, with required alternative text for accessibility and an optional size.
## Properties
| Name | Required | Lightning Type | Default | Description |
| ---- | -------- | -------------- | ------- | ----------- |
| alt | Yes | `lightning__textType` | | An alternative text that describes the image content for accessibility. Maximum 125 characters; an empty string for decorative images. |
| size | No | `lightning__textType` | `auto` | The size of the image. Valid values include `auto`, `sm`, `md`, `lg`, or `full`. |
| src | Yes | `lightning__urlType` | | The absolute or relative image URL, URL-encoded. |
## Usage
Use an image to display a graphic referenced by a URL, such as a photo, illustration, diagram, or logo.
**note:** For a circular profile photo of a user or entity, use [`tile/avatar`](https://developer.salesforce.com/docs/platform/hxl/references/hxl-reference-about/avatar.md) instead.
Set `src` to the image URL and always provide `alt` text that describes the content for accessibility.
```json
{
"definition": "tile/image",
"attributes": {
"src": "https://cdn.example.com/photo.jpg",
"alt": "Bar chart showing Q3 revenue by region"
}
}
```
Use `size` to control the image footprint. For a purely decorative image that conveys no information, set `alt` to an empty string so assistive technologies skip it.
```json
{
"definition": "tile/image",
"attributes": {
"src": "https://cdn.example.com/banner.jpg",
"alt": "",
"size": "full"
}
}
```
## Image Source
The `src` attribute must reference a resource that's accessible without authentication. To enable access to the resource, add the domain as a trusted URL. For more information, see [Use Static Resources in Widgets](https://developer.salesforce.com/docs/platform/hxl/guide/hxl-widget-composition.html#use-static-resources-in-widgets).
## Image Format
Consider these valid and invalid image types.
Valid image formats include:
- PNG
- JPEG
- GIF
- WebP
Invalid image types include:
- Vector and active content, such as `image/svg+xml`
- Non-image MIME types, such as `text/html`, `text/plain`, `application/octet-stream`, `image/bmp`, or omitted media types
### Image Schemes
`data:` scheme isn't supported when used in a link (href) context. To pass URL validation, use the `data:` scheme by following these guidelines.
### Format Requirements
Follow the `data:;base64,` syntax. The `;base64` flag is mandatory. Plain-text or raw URL-encoded data is rejected.
### Magic-Byte Signature Matching
The decoded leading bytes must match the magic bytes of the declared MIME type. For example, PNG header corresponds to `89 50 4E 47`, JPEG header `FF D8 FF`, GIF header `GIF8`, or WebP `RIFF....WEBP`.
### Decoded Size Cap
Payload must be within an 8 MiB decoded size limit (`MAX_DATA_IMAGE_BYTES`) to prevent memory amplification attacks.
### No Dynamic Expressions
Unresolved template expressions, such as `{!expr}` in either the media-type or payload slots aren't supported.
## Size
Use these `size` values to control the image footprint. The aspect ratio is always preserved. The width is fixed and the height scales to match.
- `auto` (default): Preserves the image's intrinsic dimensions.
- `sm`: Small fixed width for thumbnails and inline graphics.
- `md`: Medium fixed width for standalone images within a block of content.
- `lg`: Large fixed width for prominent, focal images.
- `full`: Fills the parent container's width, for banners and hero images.
## Design Guidelines
Consider these guidelines when working with images.
- Set `alt` to an empty string only for decorative, redundant, or structural images.
- Specify `full` to span the parent width, and `auto` when the image's own dimensions are already correct.
- Don't depend on a fixed height. The height always scales from the width to preserve the aspect ratio.
## Limitations
Note any limitations that apply to this component.
### Slackbot
No known limitations for `tile/image` in Slackbot.
### ChatGPT
No known limitations for `tile/image` in ChatGPT.
### Agentforce
No known limitations for `tile/image` in Agentforce.
## See Also
- [HXL Lightning Types Reference](https://developer.salesforce.com/docs/platform/hxl/references/hxl-lightning-types.md)
- [_HXL Playground_: Image](https://www.headlessexperiencelayer.com/#components/image)
# Link
**`tile/link`**
Shows a text-based hyperlink with a destination URL. Configure the visual style as needed.
## Properties
| Name | Required | Lightning Type | Default | Description |
| ---- | -------- | -------------- | ------- | ----------- |
| href | Yes | `lightning__urlType` | | The required absolute or relative URL string for the link destination. |
| text | No | `lightning__textType` | | Plain text for the link. When omitted, the URL is used as the text. |
| underline | No | `lightning__textType` | `hover` | The underline style for the link. Valid values include `always` for persistent underline, `hover` (default) for on-hover only, or `none` for no underline. |
| variant | No | `lightning__textType` | `primary` | Changes the appearance of the link. Valid values include `default` for standard text, `muted` for de-emphasized text, or `primary` for brand-colored text (default). |
## Usage
Use a link to send a user to a URL destination, whether an external site or an in-app route. The link renders inline clickable text styled as a hyperlink.
**note:** For an action that runs logic rather than navigating to a URL, use `tile/button` instead.
To provide a label, use the `text` attribute. For example, provide a concise action phrase such as "View pricing details", instead of a generic phrase such as "Click here".
```json
{
"definition": "tile/link",
"attributes": {
"text": "View pricing details",
"href": "https://example.com/pricing"
}
}
```
To change the emphasis of the link, use the `variant` and `underline` attributes. For example, de-emphasize the link with the `muted` variant.
```json
{
"definition": "tile/link",
"attributes": {
"text": "Terms of Service",
"href": "/terms",
"variant": "muted",
"underline": "none"
}
}
```
## Variants
Use these `variant` values to control the link's color and emphasis.
- `primary` (default): The brand accent color, for calls to action and prominent navigation.
- `default`: Inherits the surrounding text color, so the link blends into body copy and reads as running text.
- `muted`: A subdued, secondary color for supplementary or footer links that shouldn't compete with primary content.
## Underline
Use these `underline` values to control when the link's underline appears.
- `always`: Persistent underline, the traditional web-link style. Use `always` when a link sits in dense text and must be identifiable without relying on color.
- `hover` (default): Underline appears only on hover, for a cleaner default appearance.
- `none`: No underline. The link is distinguished by color alone. Use for navigation menus or styled link lists where the link role is already obvious.
## Opening in a new tab
Links always open in a new browser tab. To warn users of this context change (WCAG 3.2.2), the tile automatically appends a visible "opens in new tab" icon for sighted users and an "(opens in new tab)" cue on the accessible name for screen-reader users. You don't need to add either cue yourself — in particular, don't place your own `open-in-new` icon next to a link.
## Design Guidelines
Consider these guidelines when working with links.
- Use the `muted` variant on supplementary or footer links so they don't compete with primary content.
- Set `underline` to `always` when a link sits inside dense body text and must be identifiable without relying on color.
- Don't add an "opens in new tab" icon or phrase next to a link — the tile provides both cues automatically.
## Limitations
Note any limitations that apply to this component.
### Slackbot
No known limitations for `tile/link` in Slackbot.
### ChatGPT
No known limitations for `tile/link` in ChatGPT.
### Agentforce
`variant` and `underline` aren't supported.
## See Also
- [HXL Lightning Types Reference](https://developer.salesforce.com/docs/platform/hxl/references/hxl-lightning-types.md)
- [_HXL Playground_: Link](https://www.headlessexperiencelayer.com/#components/link)
# List Item
**`tile/listItem`**
Adds a single row inside a list. Use these child components: `tile/text`, `tile/link`, or `tile/icon`.
## Properties
This component has no configurable properties. Provide content through child components.
## Usage
Use a list item for a single row inside a `tile/list`. It carries the row's content with text, links, and icons while the parent list owns the spacing and markers. A list item has no attributes of its own. It shows content provided by its children.
**note:** Put the list item inside a [`tile/list`](https://developer.salesforce.com/docs/platform/hxl/references/hxl-reference-about/list.md). Markers and density come from the parent list, not the item.
```json
{
"definition": "tile/list",
"children": [
{
"definition": "tile/listItem",
"children": [
{
"definition": "tile/text",
"attributes": { "text": "Item content" }
}
]
}
]
}
```
A list item can hold several children to combine an icon, text, and a link in one row.
```json
{
"definition": "tile/listItem",
"children": [
{
"definition": "tile/icon",
"attributes": { "name": "info", "size": "sm" }
},
{
"definition": "tile/text",
"attributes": { "text": "See the documentation for details: " }
},
{
"definition": "tile/link",
"attributes": { "text": "Read more", "href": "https://example.com" }
}
]
}
```
## Design Guidelines
Consider these guidelines when working with list items.
- Compose each row from `tile/text`, `tile/link`, and `tile/icon` children rather than putting content directly on the item.
- To make a whole row clickable, attach an action to the item rather than wrapping its contents in a separate control.
## Limitations
Note any limitations that apply to this component.
### Slackbot
No known limitations for `tile/listItem` in Slackbot.
### ChatGPT
No known limitations for `tile/listItem` in ChatGPT.
### Agentforce
No known limitations for `tile/listItem` in Agentforce.
## See Also
- [HXL Lightning Types Reference](https://developer.salesforce.com/docs/platform/hxl/references/hxl-lightning-types.md)
- [_HXL Playground_: List Item](https://www.headlessexperiencelayer.com/#components/listItem)
# List Tile
**`tile/list`**
Shows a series of related items in a column. Use the `tile/listItem` child component for each item.
## Properties
| Name | Required | Lightning Type | Default | Description |
| ---- | -------- | -------------- | ------- | ----------- |
| marker | No | `lightning__textType` | `none` | The leading marker style for each list item. Valid values include `none`, `bullet`, or `number`. |
## Usage
Use a list to arrange a series of related items in a single vertical column with consistent spacing that reads top to bottom. The list provides only the structural framing and optional leading markers. Each row is a `tile/listItem` that carries the actual content. Keep lists to between 1 and 10 items.
**note:** A list itself holds no content. Put text, links, and icons inside each [`tile/listItem`](https://developer.salesforce.com/docs/platform/hxl/references/hxl-reference-about/listItem.md), not directly on the list.
By default, the list doesn't use a marker, such as a bullet or number. To use a disc-style bullet, specify `"marker": "bullet"`.
```json
{
"definition": "tile/list",
"attributes": { "marker": "bullet" },
"children": [
{
"definition": "tile/listItem",
"children": [
{
"definition": "tile/text",
"attributes": { "text": "Set up your environment" }
}
]
},
{
"definition": "tile/listItem",
"children": [
{
"definition": "tile/text",
"attributes": { "text": "Install dependencies" }
}
]
}
]
}
```
A list item can hold more than one child to show a title with supporting detail. For a title plus supporting line, stack two `tile/text` children within the item rather than splitting across rows. The two text children stack horizontally inside the single list item.
```json
{
"definition": "tile/list",
"children": [
{
"definition": "tile/listItem",
"children": [
{
"definition": "tile/text",
"attributes": { "text": "Set up your environment", "variant": "bold" }
},
{
"definition": "tile/text",
"attributes": {
"text": "Install Node.js 20+ and pnpm",
"variant": "caption",
"color": "muted"
}
}
]
}
]
}
```
## Marker
Use these `marker` values to set the marker shown on each list item.
- `none` (default): No marker. Use the default for plain stacks of rows where order and decoration don't add meaning.
- `bullet`: A bullet before each item for unordered sets where items are peers, such as features or options.
- `number`: Sequential numbering (1, 2, 3…) for ordered sequences such as steps or rankings where position matters.
## Design Guidelines
Consider these guidelines when working with lists.
- Keep lists short. Consider a "see more" or a summarized view if there are more than 10 items.
- For a horizontal arrangement of items rather than a vertical column, use `tile/row` instead.
## Limitations
Note any limitations that apply to this component.
### Slackbot
No known limitations for `tile/list` in Slackbot.
### ChatGPT
No known limitations for `tile/list` in ChatGPT.
### Agentforce
No known limitations for `tile/list` in Agentforce.
## See Also
- [HXL Lightning Types Reference](https://developer.salesforce.com/docs/platform/hxl/references/hxl-lightning-types.md)
- [_HXL Playground_: List Tile](https://www.headlessexperiencelayer.com/#components/list)
# Markdown
**`tile/markdown`**
Shows Markdown-formatted text content, including headings, lists, links, images, code blocks, tables, and standard inline formatting.
## Properties
| Name | Required | Lightning Type | Default | Description |
| ---- | -------- | -------------- | ------- | ----------- |
| source | Yes | `lightning__markdownTextType` | | A raw Markdown text string. Use Markdown syntax for headings, links, lists, code blocks, tables, and standard formatting. |
## Usage
Render a block of markdown-formatted text — headings, emphasis, links, images, lists, code blocks, blockquotes, and GFM tables — from a single `source` string. Use markdown when you have rich, formatted text to display.
**note:** For preformatted source code or a fenced code block, use [`tile/code`](https://developer.salesforce.com/docs/platform/hxl/references/hxl-reference-about/code.md) instead. For plain, unformatted text, use [`tile/text`](https://developer.salesforce.com/docs/platform/hxl/references/hxl-reference-about/text.md) instead.
Embed newlines as `\n` in the `source` string. Extra whitespace is removed from the formatted text.
```json
{
"definition": "tile/markdown",
"attributes": {
"source": "# Heading\n\nSome **bold** and _italic_ text with a [link](https://example.com).\n\n- First item\n- Second item"
}
}
```
To create a table, use standard CommonMark syntax or GitHub-flavored markdown.
```json
{
"definition": "tile/markdown",
"attributes": {
"source": "| Tile | Status |\n| --- | --- |\n| Text | Beta |\n| Markdown | Beta |"
}
}
```
Consider these guidelines when working with markdown.
- Task lists (`- [ ]`) aren't supported.
- Don't use inline HTML because some tags are removed from the output.
## Limitations
Note any limitations that apply to this component.
### Slackbot
No known limitations for `tile/markdown` in Slackbot.
### ChatGPT
No known limitations for `tile/markdown` in ChatGPT.
### Agentforce
No known limitations for `tile/markdown` in Agentforce.
## See Also
- [HXL Lightning Types Reference](https://developer.salesforce.com/docs/platform/hxl/references/hxl-lightning-types.md)
- [_HXL Playground_: Markdown](https://www.headlessexperiencelayer.com/#components/markdown)
# Prerequisites
Before you build with the Headless Experience Layer (HXL), set up your development environment and enable HXL in your org. Complete these prerequisites to create and deploy HXL widgets.
## Enable HXL in Your Org
HXL is available as a beta feature in API version 67.0 and later. To use HXL widgets in your org, enable the HXL beta feature.
1. From Setup, in the Quick Find box, enter `Headless Experience Layer Settings`, and then select **Headless Experience Layer Settings**.
2. Review the beta terms. To turn on the feature, select the feature toggle.
## Set Up a Salesforce DX Project
HXL widgets are source-based metadata that you develop locally and deploy to your org. Set up a Salesforce DX (SFDX) project and connect it to your Salesforce org.
- **Install the Salesforce CLI.** Use the `sf project` commands to deploy, retrieve, and track source files. See [Install Salesforce CLI](https://developer.salesforce.com/docs/atlas.en-us.sfdx_setup.meta/sfdx_setup/sfdx_setup_install_cli.htm).
- **Create or open an SFDX project.** Store your widget bundles in the `uiWidgets` folder in your project's package directory.
- **Authorize your org.** Connect the CLI to your target org so that you can deploy and retrieve metadata. See [Authorization](https://developer.salesforce.com/docs/atlas.en-us.sfdx_dev.meta/sfdx_dev/sfdx_dev_auth.htm).
## Choose How to Build Your Widgets
You can compose and preview HXL widgets in the [HXL Playground](https://developer.salesforce.com/docs/platform/hxl/guide/playground.md). Describe your UI as declarative JSON, preview it natively across surfaces, and copy the resulting widget definitions into your project. The playground is the fastest way to learn HXL concepts and prototype widgets.
Alternatively, vibe code your widgets in an AI-assisted development environment. Agentforce Vibes provides tooling to generate and refine widgets with AI assistance. To set up this environment, see [Get Started with Agentforce Vibes](https://developer.salesforce.com/docs/platform/agentforcevibes/guide/afv-get-started.html).
## Next Steps
After you complete these prerequisites, you're ready to build.
- Learn key concepts in [Build Rich UI Experiences with HXL Widgets](https://developer.salesforce.com/docs/platform/hxl/guide/build-rich-ui/hxl-rich-ui.md).
- Experiment with widgets in the [HXL Playground](https://developer.salesforce.com/docs/platform/hxl/guide/playground.md).
- Choose a target channel, either [Agentforce](https://developer.salesforce.com/docs/platform/hxl/guide/build-rich-ui/agentforce-action-output.md) or [MCP-based channels](https://developer.salesforce.com/docs/platform/hxl/guide/build-rich-ui/hxl-mcp-channels.md), such as Claude and Slackbot.
# Progress
**`tile/progress`**
Indicates task completion as a percentage, shown as a linear bar or circular ring.
## Properties
| Name | Required | Lightning Type | Default | Description |
| ---- | -------- | -------------- | ------- | ----------- |
| color | No | `lightning__textType` | `default` | The semantic color for the progress fill. Valid values include `default`, `error`, `primary`, `success`, and `warning`. |
| label | Yes | `lightning__textType` | | The required text string for the progress indicator. |
| max | No | `lightning__numberType` | | A maximum value representing 100% completion. When omitted, the value is treated as a percentage. |
| shape | No | `lightning__textType` | `linear` | The shape for the progress indicator. Valid values include `linear` (default) for a horizontal bar, `circular` for a ring or arc. |
| size | Yes | `lightning__sizeType` | | The size of the progress indicator. Valid values include `xs` for extra small, `sm` for small, `md` for medium (default), `lg` for large, or `xl` for extra large. |
| value | No | `lightning__numberType` | 0 | The current progress value. To present a percentage (0-100), omit the max value. Or provide the max value to show the current amount toward that target value. |
## Usage
Use a progress indicator to show how far along a task or process is, such as a file upload, an installation, or a quota toward a target. It renders a labeled bar or ring that fills to reflect the current `value`. The progress indicator is read-only; it reports status rather than collecting input.
**note:** For an indeterminate wait where progress can't be measured, use [`tile/spinner`](https://developer.salesforce.com/docs/platform/hxl/references/hxl-reference-about/spinner.md) instead.
To create a progress indicator, provide a `label` and a `value` from 0 to 100 as a percentage. Use a `label` that names the operation, such as "Uploading file", rather than restating the percentage.
```json
{
"definition": "tile/progress",
"attributes": {
"label": "Uploading file",
"value": 45
}
}
```
To track progress toward a non-percentage target such as a quota or item count, set `max`. The indicator fill is then computed as `value` out of `max`.
```json
{
"definition": "tile/progress",
"attributes": {
"label": "Sales quota",
"value": 1500,
"max": 2000,
"size": "lg"
}
}
```
To convey status, pair a `color` with the `value`. For example, set `color` to `success` when the task completes or `warning` as a limit approaches.
```json
{
"definition": "tile/progress",
"attributes": {
"label": "Storage usage",
"value": 85,
"color": "warning"
}
}
```
## Shape
Use `shape` to set the indicator's geometric form. Both shapes communicate the same value. Only the visual form differs.
- `linear` (default): A horizontal bar that fills left to right.
- `circular`: A ring or arc that fills clockwise, which is useful for compact spaces or overlay contexts where a bar doesn't fit.
## Size
Use `size` to set the indicator's thickness for a linear bar, or its diameter for a circular ring.
- `xs`: Extra small. Use `xs` to keep the indicator unobtrusive.
- `sm`: Small.
- `md` (default): Medium, which is suitable for most contexts.
- `lg`: Large, which gives an important or long-running task more presence.
- `xl`: Extra large, which creates a focal point when progress is the primary content.
## Color
Use `color` to set the semantic color of the progress fill. On surfaces that can't render semantic colors, the fill degrades to the default color.
- `default`: The default standard surface color with no specific status for ordinary, in-progress tasks.
- `error`: Indicates a failure or a critical threshold to reflect a problem state.
- `primary`: The brand or accent color to emphasize a featured task.
- `success`: Indicates positive completion when the task has finished successfully.
- `warning`: Indicates a caution state when a limit or threshold is approaching.
## Design Guidelines
Consider these guidelines when working with progress indicators.
- Omit `max` for a plain percentage; set it only when tracking progress toward a specific target.
- Use `color` to reinforce status, but don't rely on it alone as some surfaces render only the default fill.
## Limitations
Note any limitations that apply to this component.
### Slackbot
No known limitations for `tile/progress` in Slackbot.
### ChatGPT
No known limitations for `tile/progress` in ChatGPT.
### Agentforce
`color` is partially supported. Only `success` is native. `error` and `warning` use CSS overrides.
## See Also
- [HXL Lightning Types Reference](https://developer.salesforce.com/docs/platform/hxl/references/hxl-lightning-types.md)
- [_HXL Playground_: Progress](https://www.headlessexperiencelayer.com/#components/progress)
# Row
**`tile/row`**
Arranges child components horizontally with a configurable gap, alignment, justification, and wrapping.
## Properties
| Name | Required | Lightning Type | Default | Description |
| ---- | -------- | -------------- | ------- | ----------- |
| align | No | `lightning__alignmentType` | `center` | The cross-axis alignment for children within the row. Valid values include `start`, `center` (default), `end`, or `stretch`. |
| gap | Yes | `lightning__gapType` | | The spacing between child components. Valid values include `none` for zero, `xs` through `xl` for increasing space. The default is `md` for medium. |
| isWrapped | No | `lightning__booleanType` | true | Specifies whether the children content wrap to the next line when they exceed the row width. Default true (content-aware wrapping). |
| justify | No | `lightning__textType` | `start` | The main-axis distribution for children within the row. Valid values include `start` (default), `center`, `end`, `between`, `around`, or `evenly`. |
## Usage
Arrange child tiles horizontally, side by side, with consistent spacing between them. Use a row to make content flow left to right.
**note:** To stack content vertically instead, use [`tile/column`](https://developer.salesforce.com/docs/platform/hxl/references/hxl-reference-about/column.md).
For example, a row can include a label next to a value, a status badge beside a title, or a group of buttons.
```json
{
"definition": "tile/row",
"attributes": { "gap": "sm" },
"children": [
{
"definition": "tile/text",
"attributes": { "text": "Acme Corp", "variant": "h4" }
},
{
"definition": "tile/badge",
"attributes": { "label": "Active", "variant": "success" }
}
]
}
```
To place content on opposite ends, set `justify` to `between`. Placing content on opposite ends is a common header pattern, for example, a title on one side and an action on the other.
```json
{
"definition": "tile/row",
"attributes": { "justify": "between", "align": "center" },
"children": [
{
"definition": "tile/text",
"attributes": { "text": "Product Name", "variant": "h4" }
},
{
"definition": "tile/text",
"attributes": { "text": "$99.99", "variant": "h4", "weight": "bold" }
}
]
}
```
To build multi-column layouts, place [`tile/column`](https://developer.salesforce.com/docs/platform/hxl/references/hxl-reference-about/column.md) tiles as the direct children of a row and specify the `width` on each column. Use `width: "stretch"` on one of the columns so it absorbs the remaining horizontal space while the other columns stay content-sized.
```json
{
"definition": "tile/row",
"attributes": { "gap": "md" },
"children": [
{
"definition": "tile/column",
"attributes": { "width": "md" },
"children": [{ "definition": "tile/text", "attributes": { "text": "Sidebar" } }]
},
{
"definition": "tile/column",
"attributes": { "width": "stretch" },
"children": [{ "definition": "tile/text", "attributes": { "text": "Main content" } }]
}
]
}
```
## Alignment
Use these `align` values to position child content along the row's cross axis (vertical). This attribute applies to all child content uniformly.
- `start`: Content aligns to the top edge.
- `center` (default): Content centers vertically.
- `end`: Content aligns to the bottom edge.
- `stretch`: Content expands to fill the full row height.
## Gap
Use these `gap` values to set the spacing between child content. The gap applies uniformly between all child content. For individual spacing, use [`tile/spacer`](https://developer.salesforce.com/docs/platform/hxl/references/hxl-reference-about/spacer.md) instead.
- `none`: No spacing between child content.
- `xs`: Extra small spacing.
- `sm`: Small spacing.
- `md` (default): Medium spacing.
- `lg`: Large spacing.
- `xl`: Extra large spacing.
## Justification
Use these `justify` values to distribute child content along the row's main axis (horizontal).
- `start` (default): Content packs to the leading edge.
- `center`: Content centers as a group.
- `end`: Content packs to the trailing edge.
- `between`: Content spreads with equal space between them, with the first and last flush to the edges.
- `around`: Content spreads with equal space around each, leaving half-size space at the edges.
- `evenly`: Content spreads with exactly equal space between them and at the edges.
## Design Guidelines
Consider these guidelines when working with rows.
- Use [`tile/column`](https://developer.salesforce.com/docs/platform/hxl/references/hxl-reference-about/column.md) to make content flow top to bottom rather than left to right.
- Use `justify: "between"` for header layouts that pin a title to one side and actions to the other.
- Set `isWrapped` to `true` when a row holds a variable number of items, such as tags or badges, making the items flow onto multiple lines when space runs out.
- Nest [`tile/column`](https://developer.salesforce.com/docs/platform/hxl/references/hxl-reference-about/column.md) tiles as children and specify `width: "stretch"` on one of the columns to build a sidebar-and-main layout.
## Limitations
Note any limitations that apply to this component.
### Slackbot
No known limitations for `tile/row` in Slackbot.
### ChatGPT
No known limitations for `tile/row` in ChatGPT.
### Agentforce
No known limitations for `tile/row` in Agentforce.
## See Also
- [HXL Lightning Types Reference](https://developer.salesforce.com/docs/platform/hxl/references/hxl-lightning-types.md)
- [_HXL Playground_: Row](https://www.headlessexperiencelayer.com/#components/row)
# Schema File
The optional `schema.json` file defines the widget's attribute contract. It specifies the attributes and their associated Lightning types that the widget accepts, including display metadata (such as title and description for attribute). The Lightning types determine validation rules and data types for each attribute.
**note:** To use attribute mapping to connect your widget to a Lightning type's dynamic data, include a `schema.json` file. Without it, the widget can only display static, hardcoded values.
The schema file enables:
- Design-time validation of data bindings between Lightning types and Widgets
- Runtime binding of attributes to enable dynamic widget behavior
This table lists the keywords that you can specify for individual widget attributes.
| Keyword | Description |
| ---------------- | -------------------------------------------------------------------------------------------------------------------------------- |
| `title` | The display name for the attribute. |
| `description` | A brief explanation of the attribute's purpose. |
| `lightning:type` | The Lightning type reference for the attribute, such as `lightning__textType`, `lightning__numberType`, or `lightning__urlType`. |
This template shows the standard structural composition for defining a widget schema file.
```json
{
"title": "Widget Schema Title",
"description": "Description of the widget's attribute contract",
"properties": {
"attributes": {
"type": "object",
"properties": {
"Name": {
"title": "Display Name",
"description": "Description shown in Widget Builder",
"lightning:type": "lightning__textType"
}
}
}
}
}
```
This example shows a `schema.json` configuration file for a hotel card widget, establishing the expected data types and display metadata for the widget attributes.
```json
{
"title": "Hotel Card Widget",
"description": "Displays hotel information as a visual card",
"type": "object",
"properties": {
"attributes": {
"lightning:type": "lightning__objectType",
"properties": {
"title": {
"title": "Hotel Name",
"description": "Primary heading displayed at the top",
"lightning:type": "lightning__textType"
},
"imageUrl": {
"title": "Image URL",
"description": "URL of the hotel image",
"lightning:type": "lightning__urlType"
},
"price": {
"title": "Price Per Night",
"description": "Nightly rate displayed as currency",
"lightning:type": "lightning__numberType"
},
"description": {
"title": "Description",
"description": "Short description of the hotel",
"lightning:type": "lightning__textType"
}
}
}
}
}
```
# Separator
**`tile/separator`**
Adds a visual boundary between content sections by using a horizontal or vertical line.
## Properties
| Name | Required | Lightning Type | Default | Description |
| ---- | -------- | -------------- | ------- | ----------- |
| orientation | No | `lightning__textType` | `horizontal` | The axis of the dividing line. Valid values include `horizontal` (default) or `vertical`. |
## Usage
Use a separator to mark a boundary between sections of content with a visible line. A separator is useful as a thematic break between groups of related content, between list sections, or inside a toolbar.
**note:** The separator adds spacing with a visible line. To add spacing without a visible line, use [`tile/spacer`](https://developer.salesforce.com/docs/platform/hxl/references/hxl-reference-about/spacer.md) instead.
A separator inherits its length from the container it sits in: a `horizontal` separator spans the full width of its parent, and a `vertical` separator spans the full height.
To include a horizontal separator between vertical groups of text, use `tile/separator` as a child of `tile/column`.
```json
{
"definition": "tile/column",
"children": [
{ "definition": "tile/text", "attributes": { "text": "Account details" } },
{ "definition": "tile/separator" },
{ "definition": "tile/text", "attributes": { "text": "Billing details" } }
]
}
```
To place a vertical separator between items arranged in a row, use `tile/separator` as a child of `tile/row` and specify `"orientation": "vertical"`.
```json
{
"definition": "tile/row",
"attributes": { "gap": "sm" },
"children": [
{ "definition": "tile/text", "attributes": { "text": "Drafts" } },
{ "definition": "tile/separator", "attributes": { "orientation": "vertical" } },
{ "definition": "tile/text", "attributes": { "text": "Sent" } }
]
}
```
## Orientation
Use `orientation` to set the axis of the dividing line. By default the separator is `horizontal`, matching the most common case of breaking up vertically stacked content.
- `horizontal`: A left-to-right line spanning the container width. Use to break between vertically stacked content, such as sections in a column.
- `vertical`: A top-to-bottom line spanning the container height. Use to break between horizontally arranged content, such as items in a row or a toolbar.
## Design Guidelines
Consider these guidelines when working with separators.
- Use a separator only when a visible line aids comprehension. For routine spacing between elements, use `gap` on the `tile/row` or `tile/column` parent container.
- Match `orientation` to the parent layout. For example, use `vertical` inside a row, and `horizontal` inside a column, so the line spans the intended axis.
- Avoid stacking multiple separators with no content between them.
## Limitations
Note any limitations that apply to this component.
### Slackbot
No known limitations for `tile/separator` in Slackbot.
### ChatGPT
No known limitations for `tile/separator` in ChatGPT.
### Agentforce
No known limitations for `tile/separator` in Agentforce.
## See Also
- [HXL Lightning Types Reference](https://developer.salesforce.com/docs/platform/hxl/references/hxl-lightning-types.md)
- [_HXL Playground_: Separator](https://www.headlessexperiencelayer.com/#components/separator)
# Set Up Your Org for MCP Access
Before AI clients can connect to your Salesforce org through MCP, configure authentication and access. This one-time setup enables any MCP-compatible client to connect securely using OAuth 2.0. If you're using an existing MCP server, you've likely already completed these tasks.
Configure these items in your org:
- **External Client App** — Register an External Client App (ECA) in your org to handle OAuth authentication. This provides the authentication credentials that clients use to connect to your org.
- **OAuth Scopes** — Grant the permissions that MCP servers need to access Salesforce data and operations on behalf of authenticated users.
- **Security Settings** — Enable Proof Key for Code Exchange (PKCE) and JWT-based tokens to ensure secure, standards-based authentication.
See [Set Up Your Org](https://developer.salesforce.com/docs/platform/hosted-mcp-servers/guide/setup-overview.html) in the _Hosted MCP Servers_ guide for complete details.
**important:** When you create the ECA, note the OAuth consumer key (also known as client ID) because you'll use it later to configure your MCP client.
After your org is configured for MCP access, connect your MCP clients (Claude, Slackbot, etc) to it. Then test the widget! See [Connect your MCP client to your org](https://developer.salesforce.com/docs/platform/hxl/guide/hxl-mcp-setup-client.md).
## See Also
- [Salesforce Hosted MCP Servers](https://developer.salesforce.com/docs/platform/hosted-mcp-servers/guide/hosted-mcp-servers-overview.html)
- [Salesforce Help: External Client Apps](https://help.salesforce.com/s/articleView?id=xcloud.external_client_apps.htm&type=5)
# Spacer
**`tile/spacer`**
Adds an empty layout element that creates explicit space or flexible fill between sibling components.
## Properties
| Name | Required | Lightning Type | Default | Description |
| ---- | -------- | -------------- | ------- | ----------- |
| size | No | `lightning__textType` | `md` | The amount of space to insert between content sections. Valid values include `xs` through `xl` for fixed sizes, `fill` to grow and consume remaining space. The default is `md` for medium. |
## Usage
Use a spacer to add explicit, invisible space between sibling components, or to push siblings apart so they sit at opposite edges of their container. A spacer is purely a layout element with no visible appearance and no semantic meaning.
**note:** For even spacing applied to every child at once, set `gap` on the parent [`tile/row`](https://developer.salesforce.com/docs/platform/hxl/references/hxl-reference-about/row.md) or [`tile/column`](https://developer.salesforce.com/docs/platform/hxl/references/hxl-reference-about/column.md) instead of inserting spacers between them. To add space with a visible dividing line, use [`tile/separator`](https://developer.salesforce.com/docs/platform/hxl/references/hxl-reference-about/separator.md).
A spacer expands along the parent's main axis, which results in horizontal spacing inside a row, and vertical spacing inside a column.
To add a fixed amount of vertical space between stacked components, use `tile/spacer` as a child of `tile/column`.
```json
{
"definition": "tile/column",
"attributes": { "gap": "none" },
"children": [
{ "definition": "tile/text", "attributes": { "text": "Account details" } },
{ "definition": "tile/spacer", "attributes": { "size": "lg" } },
{ "definition": "tile/text", "attributes": { "text": "Billing details" } }
]
}
```
To pin one component to the start and another to the end of a row, place a `fill` spacer between them.
```json
{
"definition": "tile/row",
"attributes": { "align": "center" },
"children": [
{ "definition": "tile/text", "attributes": { "text": "Page Title", "variant": "h3" } },
{ "definition": "tile/spacer", "attributes": { "size": "fill" } },
{ "definition": "tile/button", "attributes": { "label": "Action" } }
]
}
```
## Size
Use `size` to control how much space the spacer occupies. Each renderer maps the fixed sizes to its own spacing scale, so exact pixel amounts vary across surfaces.
- `xs`: Extra small fixed space. Use for the tightest separation between closely related elements.
- `sm`: Small fixed space.
- `md` (default): Medium fixed space, the default.
- `lg`: Large fixed space.
- `xl`: Extra large fixed space. Use to set apart major sections.
- `fill`: Grows to consume all remaining space in the parent, pushing adjacent siblings to opposite edges. Multiple `fill` spacers in the same parent share the remaining space equally. For example, placing one on each side of an element centers it.
## Design Guidelines
Consider these guidelines when working with spacers.
- For uniform spacing between all child content, use `gap` on the `tile/row` or `tile/column` parent container.
- Use a spacer for spacing or for `fill` behavior that `gap` can't express.
- Use `size: fill` to push siblings to opposite edges of a row or column rather than guessing a fixed size that only works at one width.
## Limitations
Note any limitations that apply to this component.
### Slackbot
No known limitations for `tile/spacer` in Slackbot.
### ChatGPT
No known limitations for `tile/spacer` in ChatGPT.
### Agentforce
No known limitations for `tile/spacer` in Agentforce.
## See Also
- [HXL Lightning Types Reference](https://developer.salesforce.com/docs/platform/hxl/references/hxl-lightning-types.md)
- [_HXL Playground_: Spacer](https://www.headlessexperiencelayer.com/#components/spacer)
# Spinner
**`tile/spinner`**
Shows an indeterminate circular loading indicator. Configure the accessible label and an optional size.
## Properties
| Name | Required | Lightning Type | Default | Description |
| ---- | -------- | -------------- | ------- | ----------- |
| label | Yes | `lightning__textType` | | The accessible text that identifies the operation that's in progress. |
| size | No | `lightning__textType` | `md` | The size of the spinner. Valid values include `xs` for extra small, `sm` for small, `md` for medium (default), `lg` for large, or `xl` for extra large. |
## Usage
Use a spinner to show an indeterminate loading indicator for an operation whose duration or completion can't be measured, such as a network request, a page load, or server processing. The spinner renders a circular animation without a percentage.
**note:** For measurable progress such as uploads or multi-step flows, use [`tile/progress`](https://developer.salesforce.com/docs/platform/hxl/references/hxl-reference-about/progress.md) instead.
Provide a `label` describing what's loading so the operation is announced to assistive technology.
```json
{
"definition": "tile/spinner",
"attributes": { "label": "Loading results" }
}
```
To pair a spinner with status text, place both in a row.
```json
{
"definition": "tile/row",
"attributes": { "gap": "sm" },
"children": [
{
"definition": "tile/spinner",
"attributes": { "size": "sm", "label": "Saving changes" }
},
{
"definition": "tile/text",
"attributes": { "text": "Saving changes…" }
}
]
}
```
## Size
Use these `size` values to set the spinner's relative scale. The default is `md`.
- `xs`: Extra small spinner for inline or compact contexts such as inside a button or a form field.
- `sm`: Small spinner for inline or alongside short status text.
- `md` (default): Medium spinner for standard, in-content loading.
- `lg`: Large spinner for prominent or section-level loading.
- `xl`: Extra large spinner for page-level loading indicators.
## Design Guidelines
Consider these guidelines when working with spinners.
- Set a concise, action-oriented `label` such as "Loading results" or "Processing payment".
- Use a small spinner (`xs` or `sm`) next to buttons or form fields, and a larger size (`lg` or `xl`) for page- or section-level loading.
- Avoid placing multiple spinners in the same view — a single loading indicator reads more clearly than several competing animations.
## Limitations
Note any limitations that apply to this component.
### Slackbot
No known limitations for `tile/spinner` in Slackbot.
### ChatGPT
No known limitations for `tile/spinner` in ChatGPT.
### Agentforce
`size: xl` renders the same as `size: lg`. SLDS provides four spinner sizes only.
## See Also
- [HXL Lightning Types Reference](https://developer.salesforce.com/docs/platform/hxl/references/hxl-lightning-types.md)
- [_HXL Playground_: Spinner](https://www.headlessexperiencelayer.com/#components/spinner)
# Table
**`tile/table`**
Shows tabular data with column definitions and row data. Columns define structure (key, header, alignment). Rows are key-value objects mapping column keys to cell values.
## Properties
| Name | Required | Lightning Type | Default | Description |
| ---- | -------- | -------------- | ------- | ----------- |
| appearance | No | `lightning__textType` | `default` | The visual style for the table. Valid values include `default` for standard, `bordered` for emphasized cell borders, or `striped` for alternating row backgrounds. |
| caption | Yes | `lightning__textType` | | Accessible description of the table content and purpose. |
| columns | Yes | `lightning__listType` | | Defines the column with a key (data field identifier), header (display text), and optional alignment. The column order determines the display order. |
| isStickyHeader | No | `lightning__booleanType` | false | Specifies whether the header row remains fixed at the top during vertical scrolling. |
| pagination | No | `lightning__objectType` | | Optional pagination configuration. When provided, the table shows pagination controls and one page of data at a time. |
| rows | Yes | `lightning__listType` | | Array of data objects. Each object's keys correspond to column key values; values are cell content strings. |
| size | No | `lightning__textType` | `md` | The cell density for the table. Valid values include `sm` for compact, or `md` (default) for standard. |
| sort | No | `lightning__objectType` | | Initial sort state identifying a column key and direction. When present, a sort indicator appears in the column header. |
## Usage
Use a table to present structured data across rows and columns, such as a list of records, a price sheet, or a status report.
Define the shape with `columns`. Each column has a `key` that maps to a field in the row data and a `header` for the display label. Provide the data as `rows`, where each object's keys match the column keys. Always set `caption` to describe the table's contents for accessibility.
```json
{
"definition": "tile/table",
"attributes": {
"columns": [
{ "key": "name", "header": "Name" },
{ "key": "email", "header": "Email" },
{ "key": "role", "header": "Role" }
],
"rows": [
{ "name": "John Doe", "email": "john@example.com", "role": "Admin" },
{ "name": "Jane Smith", "email": "jane@example.com", "role": "User" }
],
"caption": "Employee contact information"
}
}
```
To render a column as something other than plain text, set its `columnType` value as described in the [Column Type](#column-type) section. Right-align numeric columns with `align` so the digits line up.
```json
{
"definition": "tile/table",
"attributes": {
"columns": [
{ "key": "id", "header": "ID" },
{ "key": "product", "header": "Product" },
{
"key": "price",
"header": "Price",
"align": "right",
"columnType": {
"type": "number",
"format": "currency",
"currencyCode": "USD",
"minimumFractionDigits": 2
}
}
],
"rows": [
{ "id": "1", "product": "Widget A", "price": 29.99 },
{ "id": "2", "product": "Widget B", "price": 39.99 }
],
"caption": "Product price list",
"appearance": "striped"
}
}
```
To break a long data set into pages, add `pagination` with a `pageSize`.
```json
{
"definition": "tile/table",
"attributes": {
"columns": [{ "key": "name", "header": "Name" }],
"rows": [],
"caption": "Team members",
"pagination": { "pageSize": 20 }
}
}
```
To keep column headers visible while the body scrolls, set `isStickyHeader` to `true`.
```json
{
"definition": "tile/table",
"attributes": {
"columns": [{ "key": "name", "header": "Name" }],
"rows": [],
"caption": "Team members",
"isStickyHeader": true
}
}
```
To show which column the data is sorted by, set `sort` to a `{ key, direction }` object, and mark columns `isSortable` so users can re-sort by clicking a header.
```json
{
"definition": "tile/table",
"attributes": {
"columns": [
{ "key": "name", "header": "Name", "isSortable": true },
{ "key": "createdDate", "header": "Created", "isSortable": true }
],
"rows": [],
"caption": "Records",
"sort": { "key": "createdDate", "direction": "desc" }
}
}
```
To enable row filtering, mark columns `isFilterable`, which adds each one to a filter panel with an input matched to its type: text search for text and link columns, a dropdown for picklist columns, a min-max range for number columns, and a date range for date columns.
```json
{
"definition": "tile/table",
"attributes": {
"columns": [
{ "key": "name", "header": "Name", "isFilterable": true },
{
"key": "status",
"header": "Status",
"isFilterable": true,
"columnType": {
"type": "picklist",
"options": [
{ "label": "Open", "value": "open" },
{ "label": "Closed", "value": "closed" }
]
}
}
],
"rows": [],
"caption": "Support tickets"
}
}
```
## Column Type
Set the `columnType` on a column to render its cells as something other than plain text. If you don't set `columnType`, cells render as plain text by default.
- `date`: Formats ISO 8601 date strings or numeric timestamps as localized dates or datetimes. Control the output with `format`, `dateStyle`, and `timeStyle`.
- `link`: Renders cell values as clickable hyperlinks. Set `urlKey` to point at a separate row field for the URL when the display text and the URL destination differ. Otherwise, the cell value serves as both.
- `number`: Formats numeric values with locale-aware `decimal`, `percent`, or `currency` formatting, and sorts numerically rather than lexicographically. Currency accepts `currencyCode` and `currencyDisplayAs`. Set fraction digits with `minimumFractionDigits` and `maximumFractionDigits`.
- `picklist`: Resolves stored row values to human-readable labels from a defined set of `options`, each a `{ label, value }` pair. A value with no matching option falls back to the raw value.
## Appearance
Use these `appearance` values to control the table's border and row treatment.
- `default` (default): Standard presentation with minimal horizontal row dividers, for most tables.
- `bordered`: Emphasized borders on all cell edges. Use `bordered` for dense data where clear cell boundaries aid readability.
- `striped`: Alternating row background colors. Use `striped` for wide tables where the shading helps readers track across a row.
## Size
Use these `size` values to control the cell density.
- `sm`: Compact cell padding for space-constrained contexts such as chat, or for dense data that fits more rows at once.
- `md` (default): Standard, comfortable cell padding for most tables.
## Design Guidelines
Consider these guidelines when working with tables.
- Always write a `caption` that names what the table contains, such as "Open support tickets," which identifies its purpose.
- Match each column `key` to a field present in every row. A key with no matching field renders as an empty cell.
- Right-align numeric columns with `align: "right"` so decimal points line up, and reserve `center` for short categorical values.
- Use `pagination` and `isStickyHeader` on long data sets, so the table stays scannable rather than overwhelming the surface.
## Limitations
Note any limitations that apply to this component.
### Slackbot
No known limitations for `tile/table` in Slackbot.
### ChatGPT
No known limitations for `tile/table` in ChatGPT.
### Agentforce
Per-column `isSortable` and `isFilterable` properties require imperative handlers. `pagination` is handled via manual data slicing rather than a built-in control.
## See Also
- [HXL Lightning Types Reference](https://developer.salesforce.com/docs/platform/hxl/references/hxl-lightning-types.md)
- [_HXL Playground_: Table](https://www.headlessexperiencelayer.com/#components/table)
# Text
**`tile/text`**
Shows text content with optional typography styling. Configure the appearance by using variant, weight, color, italic, and strikethrough settings.
## Properties
| Name | Required | Lightning Type | Default | Description |
| ---- | -------- | -------------- | ------- | ----------- |
| color | No | `lightning__textType` | `default` | A semantic color for the text, which defaults to the surface's standard text color. |
| isItalic | No | `lightning__booleanType` | false | Specifies whether the text is rendered in an italic style. |
| isStrikethrough | No | `lightning__booleanType` | false | Specifies whether the text is rendered with a strikethrough. |
| text | Yes | `lightning__multilineTextType` | | Plain text in a paragraph by default. Any inline markup or formatting syntax are removed. |
| variant | No | `lightning__textType` | `body` | The semantic typography level to determine the heading level or text role. The default is `body`. |
| weight | No | `lightning__textType` | | The font weight for the text. Omit this setting to use the variant's default weight. |
## Usage
Use `tile/text` for plain, styled text content or a simple string without markup.
**note:** For rich formatted content with markup, lists, or links, use [`tile/markdown`](https://developer.salesforce.com/docs/platform/hxl/references/hxl-reference-about/markdown.md) instead.
```json
{
"definition": "tile/text",
"attributes": {
"text": "Your order has shipped."
}
}
```
To specify a semantic role, use the `variant` attribute to specify a value for body text, code, or a heading level. You can also specify the font weight using the `weight` attribute.
```json
{
"definition": "tile/text",
"attributes": {
"text": "Account balance",
"variant": "h2",
"weight": "semibold"
}
}
```
## Variants
Use these `variant` values to express hierarchy or role. Styling on variants can vary across surfaces.
- `body` (default): Standard paragraph text
- `caption`: Small supplementary text
- `code`: Text that represents code, technical identifiers, or commands
- `h1`: The main heading on a page
- `h2`: The second heading
- `h3`: The third heading
- `h4`: The fourth heading
- `h5`: The fifth heading
- `h6`: The sixth heading
Consider these guidelines when working with text.
- Use `color` for semantic states like `error`, `success`, or `muted` instead of embedding presentational styling in the string.
- Use `isItalic` for emphasis and `isStrikethrough` for content that's superseded or deleted.
## Limitations
Note any limitations that apply to this component.
### Slackbot
No known limitations for `tile/text` in Slackbot.
### ChatGPT
No known limitations for `tile/text` in ChatGPT.
### Agentforce
No known limitations for `tile/text` in Agentforce.
## See Also
- [HXL Lightning Types Reference](https://developer.salesforce.com/docs/platform/hxl/references/hxl-lightning-types.md)
- [_HXL Playground_: Text](https://www.headlessexperiencelayer.com/#components/text)
# Use Agentforce Vibes to Build HXL Widgets
Agentforce Vibes provides the `platform-widget-generate` skill that generates HXL widgets. The skill drafts a complete `UiWidgetBundle`, which includes the widget composition file, the `schema.json` attribute contract, and the `.uiwidget-meta.xml` configuration file.
For full details on the specific instructions and the skill's capabilities, see the `platform-widget-generate` skill in the [Salesforce Skills Library on GitHub](https://github.com/forcedotcom/sf-skills/tree/main/skills/platform-widget-generate).
## Supported Capabilities for the HXL Widget Skill
When you build HXL widgets with Agentforce Vibes, you can:
- **Generate complete bundles**: Describe a widget in natural language, and the skill outputs the composition file, `schema.json`, and `.uiwidget-meta.xml` file together in the `uiWidgets` folder.
- **Bind to your data**: The skill maps each attribute in `schema.json` to a component in the composition file and wires the bindings with `{!$attrs.attributeName}` token expressions.
- **Iterate in real time**: Refine a widget through follow-up prompts in your active session, and the skill updates the local files as you go.
- **Reuse existing metadata**: Generate a widget from metadata that you retrieve and provide, such as a custom Lightning type's `schema.json`.
## Set Up Your Development Environment
1. Install the Salesforce Extension Pack for Visual Studio Code (VS Code). See [Set Up the Agentforce Vibes Extension](https://developer.salesforce.com/docs/platform/agentforcevibes/guide/afv-get-started.html).
2. Complete the HXL prerequisites, including a connected Salesforce DX project with a `uiWidgets` folder. See [Prerequisites](https://developer.salesforce.com/docs/platform/hxl/guide/prerequisites.md).
To verify which skills are active, click the **Skills** icon at the bottom of the Agentforce Vibes panel.
## Create a Lightning Type
A widget is useful only when it's associated with something that produces data, such as an action in Agentforce, or a tool on a custom MCP server. The custom Lightning type is what makes that association possible.
**note:** Vibe coding an MCP server isn't currently supported.
Consider these differences.
- The `schema.json` file in the **Lightning type** defines the **data structure** and the rules for its validation, such as maximum length, type, and format. See [Building Blocks of a Lightning Type](https://developer.salesforce.com/docs/platform/lightning-types/guide/lightning-types-core.html#building-blocks-of-a-lightning-type).
- The `schema.json` file in **widgets** 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. See [Attribute Contract](/docs/platform/hxl/references/hxl-reference-about/hxl-widgets-glossary.html#attribute-contract).
### Generate an Apex-Based Lightning Type
Before you generate a widget, [generate the custom Lightning type](https://developer.salesforce.com/docs/platform/lightning-types/guide/lightning-types-skills.html). When you later prompt Agentforce Vibes to generate a widget, the `platform-widget-generate` skill discovers the existing Lightning type in your local project and maps its properties to the widget's attributes.
For example, run this prompt in the Agentforce Vibes chat interface to generate an Apex-based Lightning type and its supporting Apex classes:
**Create an Apex-based Lightning type hotelInfo with hotel name, image URL, price, and description as its attributes.**
Agentforce Vibes invokes the `platform-custom-lightning-type-generate` skill to create the Lightning type bundle.
**note:** The `platform-custom-lightning-type-generate` skill generates the Apex-based custom Lightning types based on an Apex class that's already present in the org. If the Apex class doesn't exist, Agentforce Vibes provides you the option to create the Apex class by using a different skill.
To connect a widget to a Lightning type's dynamic data through [attribute mapping](https://developer.salesforce.com/docs/platform/hxl/guide/build-rich-ui/hxl-rich-ui.md#connect-your-widget-to-a-custom-lightning-type), the widget bundle must include a `schema.json` file. Without it, the widget displays only static, hardcoded values.
## Generate a Widget
After the Lightning type exists in your local project, open the Agentforce Vibes panel, and enter a prompt that describes the widget that you want. Start your prompt with an action verb, and clearly describe the attributes that the widget accepts.
Based on your prompt, Agentforce Vibes automatically loads the `platform-widget-generate` skill and writes the UiWidgetBundle files to your local workspace.
Based on the previous prompt to create a Lightning type, you can run a prompt that creates a widget.
**Create a widget for the hotelInfo lightning type.**
**note:** Alternatively, you can build widgets in the [HXL Playground](https://developer.salesforce.com/docs/platform/hxl/guide/playground.md) instead of entering a prompt in Agentforce Vibes, then copy and paste its JSON to use as the renderer for any action or property type.
## Deploy the Metadata and Widget Bundles
To deploy your files to an org, start with the Apex class folder, followed by the `uiWidgets` folder and then the `lightningTypes` folder. You can run a Salesforce CLI `project deploy start` command, but you can also ask Agentforce Vibes to deploy and retrieve metadata for you. For example, run this prompt in the Agentforce Vibes chat interface:
**Deploy the Apex class and Lightning type I just created.**
For the CLI workflow and more on deploying and retrieving HXL metadata, see [Use HXL Widgets on MCP Channels](https://developer.salesforce.com/docs/platform/hxl/guide/build-rich-ui/hxl-mcp-channels.md).
## Next Steps
After you deploy the metadata bundles:
- Review the generated files to understand the widget structure. See [Build Rich UI](https://developer.salesforce.com/docs/platform/hxl/guide/build-rich-ui/hxl-rich-ui.md).
- Preview and refine widgets in the [HXL Playground](https://developer.salesforce.com/docs/platform/hxl/guide/playground.md).
## Limitations
The skill has these constraints:
- The skill generates widgets from the properties that you describe or provide. It doesn't scan your org to discover existing widgets or metadata.
- The skill can't detect similar widgets or recommend them for reuse before you create a widget.
- You can't perform bulk updates across multiple widgets at the same time.
- The skill uses semantic styling, such as component variants and sizes, rather than pixel values.
# Use HXL Widgets as Agentforce Action Output
Present structured output from an Agentforce action as a Headless Experience Layer (HXL) widget in the conversation.
Agentforce actions can return structured output from Flow, Apex, a Prompt Template, or another supported action type. The action implementation can also call an API, retrieve information from Data Cloud, or run automation before returning structured output.
With HXL, you can present that output as an HXL widget rather than relying on the default output presentation. A custom Lightning type (CLT) represents the structured output and connects it to the HXL widget. The renderer associated with the CLT maps properties from the structured output to attributes accepted by the widget.
Let’s use the Apex-backed `Get Hotel Info` action to show how the same action output appears first in the default output presentation and then as the [Hotel Card widget](https://developer.salesforce.com/docs/platform/hxl/guide/hxl-widget-example-mapping.md). The same process applies to other supported Agentforce actions that return structured output.
### Compare LWC UI Overrides and HXL Widget Renderers
CLTs support [Lightning Web Components (LWC) UI overrides](https://developer.salesforce.com/docs/ai/agentforce/guide/lightning-types.html) to customize how output is displayed. With HXL widget support, a CLT can also use an HXL widget as its renderer. The following table shows the differences between these two configurations.
| **Aspect** | **LWC UI Override** | **HXL Widget Renderer** |
| -------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Renderer target** | The `renderer.json` file references an LWC that displays the output. | The `renderer.json` file references an HXL widget by using a value such as `@widget/c/hotelCard`. The widget is defined in a `UiWidgetBundle`. |
| **File location** | The `renderer.json` file is stored in a channel-specific folder, such as `lightningDesktopGenAi`. | The `renderer.json` file is stored at the root of the CLT folder, parallel to `schema.json`, and provides the renderer configuration for supported HXL channels. |
| **Property mapping** | The `attributes` object maps CLT properties to public properties exposed by the LWC. | The `attributes` object maps CLT properties to attributes defined in the widget's `schema.json`. |
| **UI configuration** | An LWC-based CLT configuration can use `editor.json` for input UI and `renderer.json` for output UI. | Use `renderer.json` to configure output rendering for an HXL widget reference. |
| **When to use** | Use when you want to customize the UI for a specific supported Salesforce channel, such as Lightning Experience, mobile, Enhanced Web Chat, or Experience Builder. | Use when you want the same widget to render across supported HXL surfaces, including Agentforce and external MCP clients such as Slackbot, ChatGPT, and Claude. |
For the complete widget-reference workflow, including the CLT folder structure, widget reference, and attribute mapping, see [Connect Your Widget to a Custom Lightning Type](https://developer.salesforce.com/docs/platform/hxl/guide/hxl-rich-ui.md#connect-your-widget-to-a-custom-lightning-type).
## Before You Begin
Before you configure output rendering, complete the following prerequisites. The HXL widget and CLT must be available in the target org for HXL to render the action output.
1. **Enable Agentforce and create an agent.**
You need an Agentforce agent in which you can invoke the action and view its response. To enable Agentforce and create an Agentforce Employee Agent, see [Get Started with Agentforce](https://developer.salesforce.com/workshops/agentforce-workshop/employee-agents/1-get-started?).
2. **Create an Agentforce action that returns structured output.**
The action must return the data that you want to display. Use the documentation for the **Reference Action Type** that corresponds to the underlying asset.
- For a Flow-backed action, see [Extend Agents with Flow Actions](https://developer.salesforce.com/workshops/agentforce-workshop/employee-agents/4-flow-actions-credit?).
- For an Apex-backed action, see [Extend Agents with Apex Actions](https://developer.salesforce.com/workshops/agentforce-workshop/employee-agents/6-apex-actions?).
- For a Prompt Template-backed action, see [Extend Agents with Prompt Template Actions](https://developer.salesforce.com/workshops/agentforce-workshop/employee-agents/7-prompt-template-actions?).
3. **Create a subagent and make the action available to it.**
The subagent defines the job that it performs and contains the reasoning instructions that determine when Agentforce invokes the action.
- To create a subagent, see [Create a Custom Subagent](https://help.salesforce.com/s/articleView?id=ai.agent_topics_add_custom.htm&language=en_US&type=5).
- To add the action to the subagent, see [Add an Action to a Subagent from the Asset Library](https://help.salesforce.com/s/articleView?id=ai.agent_actions_add_asset_library.htm&language=en_US&type=5).
- To add a reusable subagent to the agent, see [Add a Subagent to Your Agent from the Asset Library](https://help.salesforce.com/s/articleView?id=ai.agent_topics_add_asset.htm&language=en_US&type=5).
4. **Create an HXL widget.**
The widget defines how the structured output is presented. Its `UiWidgetBundle` contains the widget configuration, attribute schema, and visual composition. For widget concepts, metadata structure, file types, and authoring guidance, see [Build Rich UI Experiences with HXL Widgets](https://developer.salesforce.com/docs/platform/hxl/guide/hxl-rich-ui.md).
Optionally, use Salesforce formulas in the widget composition to calculate values and apply conditional logic. For formula syntax and examples, see [Use Salesforce Formulas in Widgets](https://developer.salesforce.com/docs/platform/hxl/guide/hxl-widget-composition.md#use-salesforce-formulas-in-widgets).
5. **Create or reuse a CLT and connect it to the widget.**
The CLT defines the schema for the structured action output. Its renderer references the HXL widget and maps action-output properties to attributes in the widget schema. For the configuration pattern, see **Connect Your Widget to a CLT** in [Build Rich UI Experiences with HXL Widgets](https://developer.salesforce.com/docs/platform/hxl/guide/hxl-rich-ui.md).
For more information about CLT and the `LightningTypeBundle` metadata type, see [Core Concepts of CLTs](https://developer.salesforce.com/docs/platform/lightning-types/guide/lightning-types-core.html?utm_source=chatgpt.com).
**note:** Alternatively, you can use Agentforce Vibes to generate the CLT and HXL widget metadata. See [Use Agentforce Vibes to Build HXL Widgets](https://developer.salesforce.com/docs/platform/hxl/hxl-vibes.md).
6. **Deploy the widget and CLT.**
Both components must be available in the target org before you can select the CLT in **Output Rendering**. For deployment guidance, see the following in [Build Rich UI Experiences with HXL Widgets](https://developer.salesforce.com/docs/platform/hxl/guide/hxl-rich-ui.md).
Both components must be available in the target org before you can select the CLT when you [Configure Output Rendering](#configure-output-rendering). For deployment guidance, see the following:
- [Use Salesforce CLI or Metadata API to Deploy UiWidgetBundles](https://developer.salesforce.com/docs/platform/hxl/guide/hxl-rich-ui.md#use-salesforce-cli-or-metadata-api-to-deploy-uiwidgetbundles)
- [Package Deployment Management](https://developer.salesforce.com/docs/platform/hxl/guide/hxl-widget-example-mapping.md#package-deployment-management)
- [Deployment Order](https://developer.salesforce.com/docs/platform/hxl/guide/hxl-widget-example-mapping.md#deployment-order)
Before you continue, confirm that:
- The action is added to the subagent.
- The subagent is added to the agent.
- The subagent's description and reasoning instructions identify when to invoke the action.
- The action returns the structured output that you want to display.
- The CLT schema represents the action output.
## Use an Agentforce Action
Select an Agentforce action that returns the structured data that you want to present in the widget. The action output provides the data that the CLT maps to the widget.
When you create an Agentforce action, select the **Reference Action Type** that corresponds to the underlying asset.
| **Reference Action Type** | **Use When** |
| ------------------------- | ------------------------------------------------- |
| Flow | The action is backed by an autolaunched flow. |
| Apex | The action is backed by an invocable Apex method. |
| Prompt Template | The action is backed by a prompt template. |
Depending on your org, additional **Reference Action Type** options can be available. These options can include API, Predictive Model, and Retriever. Select the type that corresponds to the asset used by your action.
The action implementation can also call an API, retrieve information from Data Cloud, run automation, or use another supported data source before returning structured output.
Here's an image that shows the **Reference Action Type** options.

For the running example, this page uses an Apex-backed action named `Get Hotel Info`. The action returns structured hotel information, but the HXL output-rendering process isn't specific to Apex or the Hotel Card example.
To create an Apex-backed action, see [Create the Apex Action](https://developer.salesforce.com/docs/platform/hxl/guide/hxl-mcp-apex.md).
Use these values for the running scenario.
| **Field** | **Value** |
| ------------------------- | ------------------ |
| Reference Action Type | `Apex` |
| Reference Action Category | `Invocable Method` |
| Reference Action | `Get Hotel Info` |

The action returns structured hotel information through an output named **Hotel Info Response**.
For the running example, `HotelInfoResponse` is the CLT used to present the action output through the Hotel Card widget.
Before you continue, confirm that the action:
- Is available to the agent.
- Can be invoked from the conversation preview.
- Returns the values that the widget displays.
- Returns an output structure represented by the deployed CLT.
### Configure Output Rendering
Apply the deployed CLT to the action output. This association tells Agentforce to use the renderer associated with the CLT when it presents the structured output. The renderer maps properties from the action output to attributes accepted by the HXL widget.
1. From Setup, in the **Quick Find** box, enter `Agentforce Assets`, and then select **Agentforce Assets**.
2. Select the **Actions** tab.
3. Open `Get Hotel Info`.
4. Locate the output named **Hotel Info Response**.
5. Edit the output.
6. Select **Show in conversation**.
7. In **Output Rendering**, select `HotelInfoResponse`.
8. Save the action.
9. Reload the agent page.
For the running scenario, the output configuration uses these values.
| **Output setting** | **Value** |
| -------------------- | -------------------------------------------------- |
| Output label | `Hotel Info Response` |
| Output API name | `hotelInfoResponse` |
| Data Type | `@apexClassType/c__GetHotelInfo$HotelInfoResponse` |
| Show in conversation | Selected |
| Output Rendering | `HotelInfoResponse` |

After you save the action, Agentforce uses the renderer associated with the `HotelInfoResponse` CLT to display the action’s structured output in the Hotel Card widget.
## Use an Agentforce Subagent
Use the configured subagent to route a matching user request to `Get Hotel Info`.
The subagent's description defines the job it handles. Its reasoning instructions tell Agentforce how and when to use the actions added to the subagent. This section assumes that the subagent was created, added to the agent, and associated with `Get Hotel Info` as described in [Before You Begin](#before-you-begin).
For the running scenario, use this configuration.
| **Setting** | **Value** |
| ----------- | ---------------------------- |
| Subagent | `Hotel Search` |
| Purpose | Handle hotel search requests |
| Action | `Get Hotel Info` |
Configure the subagent's description and reasoning instructions so that hotel-related requests are routed to `Hotel Search` and the subagent can invoke `Get Hotel Info`.
When the request contains all the information required by the action, the reasoning instructions can direct the subagent to invoke the action. If the action requires more information, configure the instructions so that the subagent obtains the required input before invoking it.

Before you continue, confirm that:
- `Hotel Search` is added to the agent.
- `Get Hotel Info` appears in the subagent's actions available for reasoning.
- The subagent's description distinguishes its job from the jobs of other subagents.
- The subagent's reasoning instructions identify when to invoke `Get Hotel Info`.
- A hotel-related request is routed to `Hotel Search`.
Here's an image that shows `Hotel Search` added to the agent.

## View the Default Action Output
Run the action before you apply custom output rendering. This verifies that Agentforce routes the request to the expected subagent, the subagent invokes the action, and the action returns the expected response.
1. Open the agent in Agentforce Builder.
2. Open the conversation preview.
3. Enter a request that invokes the action.
For the running example: `Get me details of {hotel name} in San Francisco.`
Replace `{hotel name}` with a hotel name supported by the target org.
4. Confirm that Agentforce selects `Hotel Search`.
5. Confirm that the subagent invokes `Get Hotel Info`.
6. Review the response in the conversation.
Before you apply the CLT, Agentforce presents the action result by using its default output presentation.

The structured output contains hotel information such as:
```text
Hotel Name
Hotel Image
Nightly rate
Summary
```
Use the same request and action response when you verify the rendered widget.
## View the Rendered Widget
Run the same request again to verify the configuration.
1. Open the agent in Agentforce Builder.
2. Open the conversation preview.
3. Enter the same request that you used to view the default output: `Get me details of {hotel name} in San Francisco.`
4. Confirm that Agentforce selects `Hotel Search`.
5. Confirm that the subagent invokes `Get Hotel Info`.
6. Confirm that the action returns the expected structured hotel output.
7. Confirm that Agentforce presents the action output as the Hotel Card widget.
8. Verify that the hotel information displayed by the widget corresponds to the action output.
The action continues to return the same structured output. The CLT and its renderer determine how that output is mapped to the widget and presented in the conversation.
In the running example, the Hotel Card widget displays the hotel name, hotel image, nightly rate, and summary.

The `Get Hotel Info` action output is now presented through the configured HXL widget.
### Add Button Actions to the Hotel Card
HXL widgets support button actions that send follow-up requests to the agent. In the running example, the Hotel Card includes **Confirm Reservation** and **Cancel Reservation** buttons. Each button uses `action/sendMessage` to send a follow-up request to the agent.
Before you test the buttons, make `Book Hotel` and `Cancel Reservation` available to the `Hotel Search` subagent. Configure the subagent’s reasoning instructions to handle booking and cancellation requests.
This example configures the **Confirm Reservation** button.
```json
{
"definition": "tile/button",
"attributes": {
"label": "Confirm Reservation",
"variant": "primary",
"actions": {
"click": [
{
"definition": "action/sendMessage",
"attributes": {
"content": "Confirm this reservation."
}
}
]
}
}
}
```
The **Cancel Reservation** button uses the same `actions.click` pattern with a cancellation request as its message content. When a user selects either button, `action/sendMessage` sends the configured message to the agent. The `Hotel Search` subagent’s reasoning instructions determine whether Agentforce invokes `Book Hotel` or `Cancel Reservation`.
The animation shows the reservation buttons sending follow-up requests in **Conversation Preview**.

For complete button properties, variants, examples, and surface support, see [Button](https://developer.salesforce.com/docs/platform/reference/components/button.md). For predefined action definitions and their attributes, see [`lightning__actionType`](https://developer.salesforce.com/docs/platform/reference/hxl-lightning-types.md#lightning__actiontype).
# Use HXL Widgets with Agents That Support MCP
Some AI agents use MCP to interact with data in your org, such as Claude Desktop, Slackbot, and ChatGPT. HXL widgets are compatible with the [MCP Apps](https://modelcontextprotocol.io/extensions/apps/overview) industry standard, which means that the widget works in any agent that is MCP Apps compatible.
**warning:** HXL widgets don't currently render when using [Block Kit for Slackbot](https://docs.slack.dev/block-kit/). Block Kit extends the MCP Apps protocol so MCP servers can return native Slack Block Kit JSON when Slackbot is the agent.
To use an HXL widget on channels that support MCP, you must create a custom MCP server and add associated tools and resources. You can also update an existing custom MCP server if you prefer.
**note:** In the HXL setup with MCP, we use the term _client_ to mean an external _agent_ that interacts with your Salesforce org. We also use the terms _channel_ and _surface_ to refer to the application in which that agent operates and the area encompassing its UI. For definitions, see the [Glossary](https://developer.salesforce.com/docs/platform/reference/hxl-widgets-glossary.md).
## Before You Begin
It's assumed that you've already:
- Set up your local DX developer environment, such as installing Salesforce CLI and the VS Code Salesforce extensions. See [Get Started by Creating a New DX Project](https://developer.salesforce.com/docs/atlas.en-us.sfdx_dev.meta/sfdx_dev/sfdx_dev_get_started_dx.htm). (You can ignore the Dev Hub instructions unless you plan to create a scratch org.)
- Created a local Salesforce DX project that contains the metadata files for your widget and custom lightning types.
For channels that support MCP, be sure you've created two object-based custom Lightning types. See [Connect Your Widget to a Custom Lightning Type](https://developer.salesforce.com/docs/platform/hxl/guide/hxl-rich-ui.md#connect-your-widget-to-a-custom-lightning-type).
- Authorized your Salesforce development org so you can deploy and retrieve metadata to and from it.
Use the VS Code **SFDX: Authorize an Org** command or the `org login web` Salesforce CLI command. In the Salesforce CLI command examples, we assume you gave your org the alias `my-org`.
- Deployed the widget and custom Lightning types from your DX project to your Salesforce org.
## General Workflow
Here are the general steps to use your widget on channels that support MCP:
1. [Create the Apex invocable action](https://developer.salesforce.com/docs/platform/hxl/guide/hxl-mcp-apex.md) that returns data from your org for your widget to display.
1. [Create or modify a custom MCP server](https://developer.salesforce.com/docs/platform/hxl/guide/hxl-mcp-server.md). This step includes creating the MCP tool that uses the Apex invocable action and wiring it up to the widget.
1. [Configure your org so your AI clients can access it through the custom MCP server](https://developer.salesforce.com/docs/platform/hxl/guide/hxl-mcp-setup-org.md).
1. [Connect your MCP client to your org](https://developer.salesforce.com/docs/platform/hxl/guide/hxl-mcp-setup-client.md) and test your widget on it.
## Vibe Code
These MCP topics show how to complete tasks manually, such as using a Salesforce CLI command to deploy metadata and editing XML files in the VS Code editor. We think it's useful to document all these details because you learn how all the HXL building blocks fit together, which makes it easier to troubleshoot problems. And saves you tokens.
However, you can also use Agentforce Vibes to complete many of these tasks. For example, rather than run the `project deploy start` Salesforce CLI command in a terminal to deploy new metadata, run this prompt in the Agentforce Vibes chat interface:
_Deploy the Apex class I just created._
## See Also
- [Agentforce Vibes Developer Guide](https://developer.salesforce.com/docs/platform/agentforcevibes/guide/afv-overview.html)
# Widget Configuration File
The `{widgetName}.uiwidget-meta.xml` file is a required resource in every widget bundle that specifies the widget type.
This table lists the configuration fields that you specify inside the `{widgetName}.uiwidget-meta.xml` file.
| Field | Required or Optional | Description |
| ------------- | -------------------- | -------------------------------------------------------------------------------------------------------------------------- |
| `widgetType` | Required | The widget implementation type. JSON is currently the only supported widget type and indicates a composition-based widget. |
| `masterLabel` | Optional | Name for the widget |
| `description` | Optional | Description for the widget |
This code example shows the required configuration structure for a widget configuration file.
```xml
Hotel Card
Displays hotel information as a visual card.
JSON
```
# Widget Example
Learn how to construct a hotel card widget and configure runtime data property bindings.
- [Example: Mapping a Hotel Card Widget for Agentforce](https://developer.salesforce.com/docs/platform/hxl/guide/hxl-widget-example-mapping.md)
- [Example: Mapping a Hotel Card Widget for MCP](https://developer.salesforce.com/docs/platform/hxl/guide/hxl-widget-example-mapping-mcp.md)
# Widgets Glossary of Terms
Learn more about the terms that are used for Headless Experience Layer (HXL) Widgets.
## Attribute Contract
The attributes and their associated Lightning types that a widget accepts, defined in the widget's `schema.json` file. The attribute contract specifies the Lightning types and display metadata for each widget attribute.
## Channel
The application or interaction experience, such as Claude or ChatGPT, which users interact with through different [surfaces](#surface).
See [Supported Applications and Platforms](/docs/platform/hxl/guide/hxl-rich-ui).
## Component
The atomic building unit 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`.
See [HXL Components](/docs/platform/hxl/references/hxl-reference-about/).
## Composition File
A required JSON file (`{widgetName}.json`) in every widget bundle that defines the widget's visual structure. It specifies which components render, their hierarchical nesting, ordering, and how they bind to data by using `{!$attrs.attributeName}` expressions.
## Conditional Rendering
A composition behavior that uses `meta.if` to include a component and its children when an expression evaluates to `true`. If the expression evaluates to `false`, the component and its children aren’t included in the rendered output.
## Data Binding Expression
A token expression with the syntax `{!$attrs.attributeName}` for referencing widget attributes that are defined in `schema.json`. These expressions receive actual values at run time when you connect the widget to a Lightning type through attribute mapping.
## List Iteration
A composition behavior that uses `meta.forEach` to repeat a component for each item in a collection. Use the optional `meta.forItem` property to define the current-item variable. If `meta.forItem` is omitted, the variable defaults to `$Item`.
## Meta Properties
Properties in a component’s `meta` object that control rendering behavior, such as conditional rendering and list iteration.
## MCP Payload Custom Lightning Type
An object-based custom Lightning type that defines the structure referenced by an MCP result wrapper custom Lightning type’s `outputValues` property. This term describes the custom Lightning type’s role in an MCP server tool configuration, not a category of custom Lightning type.
## MCP Result Wrapper Custom Lightning Type
An object-based custom Lightning type that represents the complete result returned by an MCP server tool, including `actionName`, `isSuccess`, and `outputValues`. This custom Lightning type contains the `renderer.json` file that maps nested payload properties to widget attributes. This term describes the custom Lightning type’s role in an MCP server tool configuration, not a category of custom Lightning type.
## Metadata API
A Salesforce API used for retrieving, deploying, creating, updating, or deleting customization information, such as UiWidgetBundles and LightningTypeBundles.
See [Understanding Metadata API](https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_intro.htm).
## Namespace
A unique identifier used to distinguish metadata components. Use the default `c` namespace for widgets created in your org (for example, `@widget/c/hotelCard`).
## Root Component
The required `widgetBody` component that serves as the primary wrapper for a widget's composition. Its definition must be set to `"tile/widget"` and contains all subsequent child components.
## Schema File
An optional JSON file (`schema.json`) in a widget bundle that defines the widget's attribute contract—the attributes the widget accepts, including their associated Lightning types and display metadata. Required for widgets that use attribute mapping to connect to Lightning types. The schema validates data connections at design time.
## Surface
The visual or tactile area where users interact with HXL widgets. A surface is the specific device or environment on which a channel is rendered, such as mobile or desktop. For example, ChatGPT on mobile and ChatGPT on desktop refer to the same channel presented on different surfaces.
## Widget Bundle
The metadata component, with the API name UiWidgetBundle, used to create and deploy widgets. It's stored in the `uiWidgets` folder and contains the composition file (`{widgetName}.json`), configuration file (`{widgetName}.uiwidget-meta.xml`), and optionally a `schema.json` file.
## Widget
A platform-independent, reusable UI composition built by assembling components in a JSON file. You can deploy widgets across supported Salesforce applications and third-party platforms.
## Widget Attribute Mapping
The configuration in a Lightning type's `renderer.json` file that connects Lightning type data properties to widget schema attributes. The mapping uses the attributes object with widget attribute names as keys and `{!$attrs.propertyName}` expressions (referencing Lightning type properties) as values.
## Widget Configuration File
A required XML file (`{widgetName}.uiwidget-meta.xml`) in every widget bundle that specifies the widget type. The `widgetType` field set to JSON indicates a composition-based widget.
## See Also
[Lightning Types Glossary](https://developer.salesforce.com/docs/platform/lightning-types/references/lightning-types/lightning-types-glossary.html)