logoAnt Design X

DesignDevelopmentComponentsX MarkdownX SDKX CardX SkillPlayground
  • Introduction
  • A2UI v0.8
  • A2UI v0.9

Introduction

@ant-design/x-card

@ant-design/x-card is a dynamic card rendering component based on the A2UI protocol, enabling AI Agents to dynamically build and render interactive UIs through structured JSON message streams.

What is A2UI?

A2UI (Agent-to-User Interface) is an open protocol that allows AI Agents to describe interaction intent through declarative JSON message sequences, which the frontend runtime dynamically renders into native UI components.

Core Design Principles

A2UI is built on three core ideas:

  1. Streaming Messages: UI updates flow from the Agent to the client as a sequence of JSON messages
  2. Declarative Components: UI is described as data, not code
  3. Data Binding: UI structure is decoupled from application state, enabling reactive updates

Why A2UI?

Unlike traditional approaches where AI generates HTML directly, A2UI uses structured data streams with significant advantages:

FeatureA2UIAI-generated HTML
SecurityOnly uses predefined component catalog, no code execution riskMay contain malicious scripts, injection risk
Cross-platformOne data structure auto-adapts to Web, mobile, and other native componentsHTML requires extra adaptation per platform
Streaming RenderingSupports progressive rendering for smooth UXRequires complete response before rendering
LLM-friendlyFlat JSON structure supports incremental generation, reduces AI burdenRequires generating full HTML structure, prone to syntax errors
MaintenanceComponents managed centrally, updates only require client library changesEach HTML interface needs individual debugging

Data Flow Architecture

A2UI follows the unidirectional data flow principle, ensuring predictable data direction:

Agent (LLM) → A2UI Generator → Transport (SSE/WebSocket/A2A)
↓
Client (Stream Reader) → Message Parser → Renderer → Native UI

Data Flow Lifecycle

Using a restaurant booking as an example:

mermaid
sequenceDiagram
participant User
participant Client
participant Agent
User->>Client: "Book a table for 2 tomorrow at 7pm"
Client->>Agent: Send user request
Note over Agent: 1. Create UI container
Agent->>Client: createSurface { surfaceId: "booking" }
Note over Agent: 2. Define UI structure
Agent->>Client: updateComponents { components: [...] }
Note over Agent: 3. Populate initial data
Agent->>Client: updateDataModel { datetime: "2025-12-16T19:00", guests: 2 }
Note over Client: 4. Render booking form
Client->>User: Show date picker and guest count input
User->>Client: Change guest count to 3
Note over Client: Auto-updates /reservation/guests
User->>Client: Click "Confirm" button
Client->>Agent: userAction { name: "confirm", context: { guests: 3 } }
Note over Agent: 5. Handle user action
Agent->>Client: deleteSurface { surfaceId: "booking" }
Agent->>Client: Create success confirmation UI

Protocol Versions

@ant-design/x-card supports both v0.8 and v0.9 of the A2UI protocol. Understanding the differences helps you choose the right version and migrate if needed.

Version Comparison

Featurev0.8v0.9
Version fieldNo explicit version fieldExplicit version: 'v0.9' field
Surface creationImplicit (auto-created on first updateComponents)Explicit createSurface command
Data model updateUses contents arrayUses path and value fields
Component definitionMore complex nested structureSimpler flat structure
RecommendationDeprecated, compatibility onlyRecommended

v0.8 Message Format (Deprecated)

v0.8 uses implicit Surface creation — a Surface is automatically created when the Agent sends the first updateComponents:

typescript
// v0.8 has no explicit version field
{
updateComponents: {
surfaceId: 'booking',
catalogId: 'https://example.com/catalogs/booking/v1/catalog.json',
components: [
{
id: 'root',
component: 'Column',
children: ['header', 'content']
}
]
}
}

Data model updates use the contents array:

typescript
{
updateDataModel: {
surfaceId: 'booking',
contents: [
{
op: 'replace',
path: '/reservation/guests',
value: 3
}
]
}
}

v0.9 Message Format (Recommended)

v0.9 introduces explicit version identification and a Surface creation command, making the protocol clearer and more controllable:

typescript
// Explicitly create Surface
{
version: 'v0.9',
createSurface: {
surfaceId: 'booking',
catalogId: 'https://example.com/catalogs/booking/v1/catalog.json'
}
}
// Update components
{
version: 'v0.9',
updateComponents: {
surfaceId: 'booking',
components: [
{
id: 'root',
component: 'Column',
children: ['header', 'content']
}
]
}
}

Data model updates use the more intuitive path and value fields:

typescript
{
version: 'v0.9',
updateDataModel: {
surfaceId: 'booking',
path: '/reservation/guests',
value: 3
}
}

Migration Guide

If you are using v0.8, follow these steps to migrate to v0.9:

1. Add Version Field

Add version: 'v0.9' to all messages:

typescript
// v0.8
{ updateComponents: { ... } }
// v0.9
{ version: 'v0.9', updateComponents: { ... } }

2. Explicitly Create Surface

Send createSurface before updateComponents:

typescript
// v0.8: implicit creation
{ updateComponents: { surfaceId: 'booking', catalogId: '...', components: [...] } }
// v0.9: explicit creation
[
{ version: 'v0.9', createSurface: { surfaceId: 'booking', catalogId: '...' } },
{ version: 'v0.9', updateComponents: { surfaceId: 'booking', components: [...] } }
]

3. Simplify Data Model Updates

Replace the contents array with path + value:

typescript
// v0.8
{
updateDataModel: {
surfaceId: 'booking',
contents: [
{ op: 'replace', path: '/guests', value: 3 }
]
}
}
// v0.9
{
version: 'v0.9',
updateDataModel: {
surfaceId: 'booking',
path: '/guests',
value: 3
}
}

4. Batch Data Updates

v0.9 supports updating entire objects, reducing message count:

typescript
// v0.8: multiple messages required
[
{ updateDataModel: { surfaceId: 'booking', contents: [{ op: 'add', path: '/date', value: '2025-12-16' }] } },
{ updateDataModel: { surfaceId: 'booking', contents: [{ op: 'add', path: '/guests', value: 2 }] } }
]
// v0.9: one message is enough
{
version: 'v0.9',
updateDataModel: {
surfaceId: 'booking',
path: '/reservation',
value: { date: '2025-12-16', guests: 2 }
}
}

Backward Compatibility

@ant-design/x-card supports both versions simultaneously:

tsx
import type { XAgentCommand_v0_8, XAgentCommand_v0_9 } from '@ant-design/x-card';
// Auto-detect version and handle correctly
const commands: (XAgentCommand_v0_8 | XAgentCommand_v0_9)[] = [
// v0.8 message
{
updateComponents: {
/* ... */
},
},
// v0.9 message
{
version: 'v0.9',
createSurface: {
/* ... */
},
},
];
<XCard.Box commands={commands}>{/* ... */}</XCard.Box>;

The component automatically detects the protocol version based on the presence of the version field and handles messages correctly.

Core Message Types

@ant-design/x-card fully implements the A2UI v0.9 core command system:

1. createSurface — Create UI Container

Creates a new UI container (Surface). Each Surface has its own independent component tree and data model.

typescript
{
version: 'v0.9',
createSurface: {
surfaceId: 'booking', // Unique surface identifier
catalogId: 'https://example.com/catalogs/booking/v1/catalog.json' // Component catalog
}
}

2. updateComponents — Update Component Structure

Defines or updates UI components in a Surface using the adjacency list model.

typescript
{
version: 'v0.9',
updateComponents: {
surfaceId: 'booking',
components: [
{ id: 'root', component: 'Column', children: ['header', 'guests-field', 'submit-btn'] },
{ id: 'header', component: 'Text', text: 'Confirm Reservation', variant: 'h1' },
{ id: 'guests-field', component: 'TextField', label: 'Guests', value: { path: '/reservation/guests' } },
{
id: 'submit-btn',
component: 'Button',
variant: 'primary',
child: 'submit-text',
action: {
event: { name: 'confirm', context: { details: { path: '/reservation' } } }
}
}
]
}
}

3. updateDataModel — Update Data Model

Updates the Surface's application state, triggering reactive UI updates.

typescript
{
version: 'v0.9',
updateDataModel: {
surfaceId: 'booking',
path: '/reservation',
value: {
datetime: '2025-12-16T19:00:00Z',
guests: 2
}
}
}

4. deleteSurface — Delete Surface

Removes the specified Surface and all its components and data model.

typescript
{
version: 'v0.9',
deleteSurface: {
surfaceId: 'booking'
}
}

Data Binding System

A2UI separates UI structure from application state, enabling reactive updates through data binding.

Data Model

Each Surface has an independent JSON data model:

json
{
"user": { "name": "Alice", "email": "alice@example.com" },
"reservation": { "datetime": "2025-12-16T19:00:00Z", "guests": 2 }
}

JSON Pointer Paths

Uses RFC 6901 standard JSON Pointer to access

  • /user/name → "Alice"
  • /reservation/guests → 2

Literal vs. Path Binding

Component properties can use literal values or data binding:

typescript
// Literal (static)
{ id: 'title', component: 'Text', text: 'Welcome' }
// Path binding (dynamic)
{ id: 'username', component: 'Text', text: { path: '/user/name' } }

When /user/name changes from "Alice" to "Bob", the text updates automatically.

Two-way Binding

Interactive components can automatically update the data model:

typescript
{ id: 'name-input', component: 'TextField', value: { path: '/form/name' } }

User input automatically updates /form/name.

Action Event Handling

User interactions are passed back to the Agent via action events.

typescript
// Component definition
{
id: 'submit-btn',
component: 'Button',
action: {
event: {
name: 'confirm_booking',
context: {
date: { path: '/reservation/datetime' },
guests: { path: '/reservation/guests' }
}
}
}
}

When the user clicks the button, the client sends:

typescript
{
version: 'v0.9',
action: {
name: 'confirm_booking',
surfaceId: 'booking',
sourceComponentId: 'submit-btn',
timestamp: '2025-12-16T19:05:00Z',
context: { date: '2025-12-16T19:00:00Z', guests: 3 }
}
}

Component Catalog

The Catalog defines available components and their property schemas, ensuring type safety and validation.

typescript
registerCatalog(catalog);
<XCard.Box
components={{
Text: MyTextComponent,
Button: MyButtonComponent,
TextField: MyTextFieldComponent,
}}
>
{/* ... */}
</XCard.Box>;

Core Features

1. Progressive Rendering

Users see the UI build up incrementally without waiting for the full response.

2. Adjacency List Model

Uses a flat component list instead of a nested tree structure — LLM-friendly, supports incremental updates, and fault-tolerant.

3. Component Validation

Automatically validates component properties against the Catalog. Friendly errors in development, graceful degradation in production.

4. Type Safety

Full TypeScript type definitions:

typescript
import type {
XAgentCommand_v0_9,
XAgentCommand_v0_8,
ActionPayload,
Catalog,
CatalogComponent,
} from '@ant-design/x-card';

Installation

bash
npm install @ant-design/x-card
# or
yarn add @ant-design/x-card
# or
pnpm add @ant-design/x-card

Quick Start

tsx
import { XCard, registerCatalog } from '@ant-design/x-card';
import type { XAgentCommand_v0_9, Catalog, ActionPayload } from '@ant-design/x-card';
const catalog: Catalog = {
catalogId: 'my-app-catalog',
components: {
Text: {
/* ... */
},
Button: {
/* ... */
},
},
};
registerCatalog(catalog);
const commands: XAgentCommand_v0_9[] = [
{ version: 'v0.9', createSurface: { surfaceId: 'booking', catalogId: 'my-app-catalog' } },
{
version: 'v0.9',
updateComponents: {
surfaceId: 'booking',
components: [
/* ... */
],
},
},
];
function App() {
const handleAction = (payload: ActionPayload) => {
console.log('Action triggered:', payload.name, payload.context);
};
return (
<XCard.Box
commands={commands}
onAction={handleAction}
components={{ Text: MyTextComponent, Button: MyButtonComponent }}
>
<XCard.Card id="booking" />
</XCard.Box>
);
}

Use Cases

  • AI Assistant UIs: Let AI Agents dynamically generate forms, cards, and interactive interfaces
  • Smart Forms: Dynamically adjust form structure and validation rules based on user input
  • Data Visualization: Dynamically generate charts, lists, and data display components
  • Workflow Orchestration: Render different stage UIs based on business processes
  • Multi-turn Conversations: Embed dynamic interactive components in chat interfaces
  • Personalized UIs: Customize UI based on user preferences and usage scenarios

Next Steps

  • See A2UI v0.9 for the latest protocol spec and examples
  • Read the A2UI Official Docs for protocol design philosophy
  • Browse Component Structure to learn the adjacency list model
  • Reference Data Binding to master reactive updates