A2UI Protocol Reference
A2UI (Agent-to-User Interface) is an open protocol for AI agents to generate safe, declarative user interfaces.
Overview
A2UI enables agents to generate native UI components instead of HTML, providing:
- Security: Declarative JSON, not executable code
- LLM-Friendly: Optimized for token-by-token generation
- Platform-Agnostic: Works with React, Flutter, Vue, Angular
- Progressive: Streams UI components as generated
- Accessible: Native components inherit host accessibility
A2UI vs HTML
| Aspect | HTML | A2UI |
|---|---|---|
| Format | <button>Click</button> | {"type": "button", "label": "Click"} |
| Security | XSS risks, script injection | Schema-validated, no execution |
| Streaming | Must complete full document | Streams JSON objects progressively |
| Type Safety | Runtime errors | Compile-time validation |
| Accessibility | Manual ARIA attributes | Native component inheritance |
| Platform | Web only | Any platform with renderer |
Protocol Flow
┌──────────────┐
│ User Request │
│ "Show status"│
└────────┬─────┘
│
▼
┌──────────────────────┐
│ Agent Processing │
│ Generates A2UI JSON │
└────────┬─────────────┘
│
A2UI Component Tree
{
"type": "container",
"children": [...]
}
│
▼
┌──────────────────────┐
│ A2UI Client Parser │
│ Validates + Renders │
└────────┬─────────────┘
│
▼
┌──────────────────────┐
│ Native UI Components │
│ (React, Flutter, etc)│
└──────────────────────┘
Component Schema
Basic Structure
{
"type": "component_type",
"properties": {...},
"children": [...]
}
Core Components
Text
{
"type": "text",
"content": "Hello, World!",
"style": "heading|body|caption"
}
Button
{
"type": "button",
"label": "Click Me",
"action": "action_name",
"variant": "primary|secondary|danger",
"disabled": false
}
Container
{
"type": "container",
"layout": "vertical|horizontal|grid",
"gap": "small|medium|large",
"children": [...]
}
Card
{
"type": "card",
"title": "Card Title",
"subtitle": "Optional subtitle",
"children": [...]
}
Table
{
"type": "table",
"columns": ["Name", "Status", "Progress"],
"rows": [
["VPC", "✅ Complete", "100%"],
["Cluster", "⏳ Running", "60%"]
]
}
List
{
"type": "list",
"ordered": false,
"items": [
{"text": "Item 1", "icon": "check"},
{"text": "Item 2", "icon": "pending"}
]
}
Progress
{
"type": "progress",
"value": 75,
"max": 100,
"label": "Deployment Progress"
}
Input
{
"type": "input",
"name": "cluster_name",
"label": "Cluster Name",
"placeholder": "Enter name...",
"required": true
}
Select
{
"type": "select",
"name": "region",
"label": "Region",
"options": [
{"value": "us-east-1", "label": "US East"},
{"value": "eu-west-1", "label": "EU West"}
]
}
Complex Examples
Status Dashboard
{
"type": "container",
"layout": "vertical",
"children": [
{
"type": "text",
"content": "Infrastructure Status",
"style": "heading"
},
{
"type": "container",
"layout": "grid",
"columns": 3,
"children": [
{
"type": "card",
"title": "VPC",
"children": [
{"type": "text", "content": "vpc-12345"},
{"type": "badge", "label": "Active", "color": "green"}
]
},
{
"type": "card",
"title": "Cluster",
"children": [
{"type": "text", "content": "eks-prod-01"},
{"type": "badge", "label": "Running", "color": "green"}
]
},
{
"type": "card",
"title": "Nodes",
"children": [
{"type": "text", "content": "5 / 5 healthy"},
{"type": "progress", "value": 100}
]
}
]
}
]
}
Approval Form
{
"type": "card",
"title": "Deployment Approval Required",
"children": [
{
"type": "text",
"content": "The following changes require your approval:",
"style": "body"
},
{
"type": "table",
"columns": ["Change", "Impact"],
"rows": [
["Add 3 nodes", "+$150/month"],
["Enable auto-scaling", "Variable cost"],
["Update security groups", "No cost"]
]
},
{
"type": "container",
"layout": "horizontal",
"gap": "medium",
"children": [
{
"type": "button",
"label": "Approve",
"action": "approve",
"variant": "primary"
},
{
"type": "button",
"label": "Reject",
"action": "reject",
"variant": "danger"
},
{
"type": "button",
"label": "Request Changes",
"action": "request_changes",
"variant": "secondary"
}
]
}
]
}
Deployment Progress
{
"type": "container",
"layout": "vertical",
"children": [
{
"type": "progress",
"value": 60,
"label": "Overall Progress"
},
{
"type": "list",
"items": [
{"text": "Build container image", "icon": "check", "status": "complete"},
{"text": "Push to registry", "icon": "check", "status": "complete"},
{"text": "Deploy to staging", "icon": "spinner", "status": "in_progress"},
{"text": "Run integration tests", "icon": "circle", "status": "pending"},
{"text": "Deploy to production", "icon": "circle", "status": "pending"}
]
}
]
}
Actions and Events
Defining Actions
{
"type": "button",
"label": "Deploy",
"action": {
"type": "submit",
"endpoint": "deploy",
"params": {
"environment": "production"
}
}
}
Action Types
| Type | Description |
|---|---|
submit | Submit form data to agent |
navigate | Navigate to another view |
dismiss | Close current modal/dialog |
confirm | Show confirmation dialog |
copy | Copy text to clipboard |
Streaming
A2UI supports progressive rendering:
Stream 1: {"type": "container", "children": [
Stream 2: {"type": "text", "content": "Loading..."},
Stream 3: {"type": "progress", "value": 0}
Stream 4: ]}
// Update as data arrives
Stream 5: {"update": {"path": "children[0]", "value": {"type": "text", "content": "Processing VPC..."}}}
Stream 6: {"update": {"path": "children[1]", "value": {"type": "progress", "value": 25}}}
Validation
Schema Validation
interface A2UIComponent {
type: string;
id?: string;
children?: A2UIComponent[];
[key: string]: any;
}
function validateComponent(component: A2UIComponent): boolean {
// Check type is registered
if (!COMPONENT_REGISTRY[component.type]) {
return false;
}
// Validate props against schema
const schema = COMPONENT_REGISTRY[component.type].schema;
return validate(component, schema);
}
Security Validation
- ✅ No script execution
- ✅ No inline styles (use predefined themes)
- ✅ No external URLs without allowlist
- ✅ Action handlers are predefined
- ✅ Sanitize all text content
React Implementation
import { A2UIRenderer, registerComponent } from '@a2ui/react';
// Register custom components
registerComponent('deployment-status', DeploymentStatusCard);
// Render A2UI JSON
function App() {
const [a2uiData, setA2uiData] = useState(null);
useEffect(() => {
// Receive A2UI from agent
agent.onMessage((data) => setA2uiData(data));
}, []);
return (
<A2UIRenderer
data={a2uiData}
onAction={(action) => agent.sendAction(action)}
theme="dark"
/>
);
}
Best Practices
- ✅ Define all components in registry at startup
- ✅ Stream JSON progressively for performance
- ✅ Include fallback components for unknown types
- ✅ Validate against schema before rendering
- ✅ Provide keyboard navigation support
- ✅ Test across platforms (web, mobile, desktop)
- ✅ Use semantic component types
- ✅ Keep component trees shallow when possible