4.4 KiB
WidgetBundle Layout
The widget skill writes three files into one directory under the project's package directory.
Folder layout
<pkgDir>/uiWidgets/<widgetName>/
<widgetName>.json # widget envelope + UEM body
schema.json # JSON Schema
<widgetName>.uiwidget-meta.xml # UiWidgetBundle registration
<widgetName> is camelCase and matches the directory name and both <widgetName>.json / <widgetName>.uiwidget-meta.xml filenames exactly.
Resolving <pkgDir>
<pkgDir> resolves to <packageDirectories[].path>/main/default — the SFDX source-format default, where <packageDirectories[].path> is the default: true entry in sfdx-project.json (or the first entry if none is marked default).
<widgetName>.json — Widget envelope + UEM body
The envelope has exactly two top-level keys — type and contentBody. The UEM tree lives at contentBody.widgetBody. Display metadata (label / description) lives in <widgetName>.uiwidget-meta.xml, not in the envelope.
{
"type": "lightning__agentforceWidget",
"contentBody": {
"widgetBody": {
"definition": "tile/widget",
"children": [
/* every block — root and non-root — carries "definition", optional "attributes", optional "meta", optional "children". No "type" key on any node. */
]
}
}
}
Envelope keys:
type— always"lightning__agentforceWidget".contentBody.widgetBody— the root UEM node; this istile/widget. It carriesdefinitionandchildrenonly — notypekey on the root, notypekey on any child.
Tree composition (everything inside widgetBody.children) is owned by SKILL.md Composition. No node — root or non-root — carries a type key.
schema.json — Input contract
JSON Schema describing what data the widget accepts at runtime. Fields are wrapped one level deep under properties.attributes.
Required root keys:
title(string) — display nametype(string) — must equal"object"properties.attributes(object) — must carrylightning:type: "lightning__objectType"and a nestedpropertiesmap whose leaves each carrylightning:type
Optional root keys:
description(string)
Each leaf under properties.attributes.properties MUST have lightning:type. Optional per-leaf: title, description.
Example:
{
"title": "Order Summary Widget",
"description": "Displays an order's id, customer, and total.",
"type": "object",
"properties": {
"attributes": {
"lightning:type": "lightning__objectType",
"properties": {
"orderId": { "title": "Order ID", "description": "Stable identifier shown in the header.", "lightning:type": "lightning__textType" },
"customer": { "title": "Customer", "description": "Display name of the customer on the order.", "lightning:type": "lightning__textType" },
"total": { "title": "Total", "description": "Order total in the order's currency.", "lightning:type": "lightning__numberType" }
}
}
}
}
{!$attrs.X} in the body resolves to properties.attributes.properties.X in the schema.
<widgetName>.uiwidget-meta.xml — Registration
<?xml version="1.0" encoding="UTF-8"?>
<UiWidgetBundle xmlns="http://soap.sforce.com/2006/04/metadata">
<masterLabel><Human display label></masterLabel>
<description><One-line description of what the widget renders></description>
<widgetType>JSON</widgetType>
</UiWidgetBundle>
Elements:
<masterLabel>— required. Human-readable label shown in the runtime UI. Prefer title-case (e.g.Account Summary Card) — not thecamelCase<widgetName>.<description>— required. One-line description of what the widget renders. Populates the display metadata previously carried in the envelope.<widgetType>— required. Only theJSONvariant is supported. TheFUNCTIONvariant is out of scope.
Validation reminders
- Every
{!$attrs.X}in<widgetName>.jsonMUST resolve to a property underschema.jsonproperties.attributes.properties(or to aforItemloop variable defined upstream). <widgetName>.uiwidget-meta.xmlMUST parse as well-formed XML, have root element<UiWidgetBundle>, and carry non-empty<masterLabel>,<description>, and<widgetType>JSON</widgetType>elements.- The three files MUST be co-located in the same
<widgetName>/directory underuiWidgets/.