Loading...
This skill helps you generate A2UI (Agent to UI) protocol compliant code for building rich, interactive user interfaces that AI agents can stream to clients.
This skill targets A2UI Protocol v0.8 (Stable Release).
Standard Catalog ID: https://github.com/google/A2UI/blob/main/specification/0.8/json/standard_catalog_definition.json
A2UI uses four message types in a JSONL stream:
| Message | Purpose |
|---------|---------|
| surfaceUpdate | Define or update UI components |
| dataModelUpdate | Populate or update application state |
| beginRendering | Signal client to start rendering |
| deleteSurface | Remove a UI surface |
Components are defined as a flat list with ID references, not nested trees:
{"surfaceUpdate": {"surfaceId": "main", "components": [
{"id": "root", "component": {"Column": {"children": {"explicitList": ["header", "content"]}}}},
{"id": "header", "component": {"Text": {"text": {"literalString": "Welcome"}, "usageHint": "h1"}}},
{"id": "content", "component": {"Text": {"text": {"path": "/user/name"}}}}
]}}
Three patterns for binding values:
// Literal only - static value
{"literalString": "Hello"}
// Path only - dynamic from data model
{"path": "/user/name"}
// Both - initialization shorthand (sets default AND binds)
{"path": "/form/email", "literalString": "user@example.com"}
Customize appearance in beginRendering:
{"beginRendering": {
"surfaceId": "main",
"root": "root",
"styles": {
"font": "Roboto",
"primaryColor": "#1976D2"
}
}}
| Property | Description |
|----------|-------------|
| font | Primary font family |
| primaryColor | Theme color (hex format #RRGGBB) |
Row - Horizontal container with distribution and alignmentColumn - Vertical container with distribution and alignmentList - Scrollable list with direction (vertical/horizontal)Card - Material card wrapper with single childTabs - Tab navigation with tabItems arrayModal - Dialog with entryPointChild and contentChildDivider - Separator with axis (horizontal/vertical)Text - Text display with usageHint (h1-h5, caption, body). Supports simple Markdown.Image - Image with url, fit, usageHintIcon - Icon from standard set (see components reference)Video - Video player with urlAudioPlayer - Audio with url and descriptionButton - Clickable with child and actionTextField - Text input with label, textFieldTypeCheckBox - Toggle with label and valueDateTimeInput - Date/time picker with enableDate/enableTimeMultipleChoice - Selection with options and maxAllowedSelectionsSlider - Range input with minValue/maxValueUse weight on components inside Row/Column for flex layout:
{"id": "sidebar", "weight": 1, "component": {"Column": {...}}},
{"id": "main", "weight": 3, "component": {"Column": {...}}}
surfaceUpdatedataModelUpdatebeginRendering{"surfaceUpdate": {"surfaceId": "booking", "components": [
{"id": "root", "component": {"Column": {"children": {"explicitList": ["title", "name_field", "date_field", "submit_btn"]}}}},
{"id": "title", "component": {"Text": {"text": {"literalString": "Book a Table"}, "usageHint": "h2"}}},
{"id": "name_field", "component": {"TextField": {"label": {"literalString": "Your Name"}, "text": {"path": "/form/name"}}}},
{"id": "date_field", "component": {"DateTimeInput": {"value": {"path": "/form/date"}, "enableDate": true}}},
{"id": "submit_btn", "component": {"Button": {"child": "submit_text", "action": {"name": "submit_booking", "context": [{"key": "name", "value": {"path": "/form/name"}}, {"key": "date", "value": {"path": "/form/date"}}]}}}},
{"id": "submit_text", "component": {"Text": {"text": {"literalString": "Confirm Booking"}}}}
]}}
{"dataModelUpdate": {"surfaceId": "booking", "contents": [{"key": "form", "valueMap": [{"key": "name", "valueString": ""}, {"key": "date", "valueString": ""}]}]}}
{"beginRendering": {"surfaceId": "booking", "root": "root"}}
When a user interacts (e.g., clicks a button), the client sends userAction:
{
"userAction": {
"name": "submit_booking",
"surfaceId": "booking",
"sourceComponentId": "submit_btn",
"timestamp": "2025-01-01T10:00:00Z",
"context": {"name": "John Doe", "date": "2025-01-15"}
}
}
Clients report errors via error message:
{
"error": {
"type": "RENDER_ERROR",
"message": "Component 'user_card' references missing child",
"surfaceId": "main",
"componentId": "user_card",
"timestamp": "2025-01-01T10:30:05Z"
}
}
id within its surfacesurfaceUpdate, dynamic values in dataModelUpdate/user/profile/name)beginRendering after essential components are defineddeleteSurface when flows completeChangelog coming soon.