com um clique
x-card
// Use when building AI-driven UIs with @ant-design/x-card — covers XCard.Box, XCard.Card, A2UI v0.9 commands, data binding, catalogs, actions, and streaming patterns.
// Use when building AI-driven UIs with @ant-design/x-card — covers XCard.Box, XCard.Card, A2UI v0.9 commands, data binding, catalogs, actions, and streaming patterns.
Focus on explaining how to use the useXChat Hook, including custom Provider integration, message management, error handling, multi-conversation management, and more
Focus on implementing custom Chat Provider, helping to adapt any streaming interface to Ant Design X standard format
Use when building AI chat UIs with @ant-design/x components — covers Bubble, Sender, Conversations, Prompts, ThoughtChain, Actions, Welcome, Attachments, Sources, Suggestion, Think, FileCard, CodeHighlighter, Mermaid, Folder, XProvider, and Notification.
Use when building or reviewing Markdown rendering with @ant-design/x-markdown, including streaming Markdown, custom component mapping, plugins, themes, and chat-oriented rich content.
Focus on explaining the practical configuration and usage of XRequest, providing accurate configuration instructions based on official documentation
专注讲解如何使用 useXChat Hook,包括自定义 Provider 的集成、消息管理、错误处理、多会话管理等
| name | x-card |
| version | 2.7.0 |
| description | Use when building AI-driven UIs with @ant-design/x-card — covers XCard.Box, XCard.Card, A2UI v0.9 commands, data binding, catalogs, actions, and streaming patterns. |
This skill covers @ant-design/x-card — the React implementation of the A2UI protocol, enabling AI agents to dynamically render rich interactive UIs through structured JSON command streams.
It covers:
XCard.Box + XCard.Card component usagecreateSurface, updateComponents, updateDataModel, deleteSurfaceScope: v0.9 is the recommended protocol. v0.8 is supported for backward compatibility only — prefer v0.9 for all new work.
| Package | Responsibility |
|---|---|
@ant-design/x-card | React renderer for A2UI protocol — XCard.Box, XCard.Card, catalog APIs |
@ant-design/x | Chat UI components (Bubble, Sender, etc.) — not covered here |
@ant-design/x-sdk | Data providers, streaming — not covered here |
npm install @ant-design/x-card
Exports:
import {
XCard,
registerCatalog,
loadCatalog,
validateComponent,
clearCatalogCache,
} from '@ant-design/x-card';
import type {
XAgentCommand_v0_9,
XAgentCommand_v0_8,
ActionPayload,
Catalog,
CatalogComponent,
} from '@ant-design/x-card';
// Subcomponents
XCard.Box; // Container: receives commands, owns catalog maps
XCard.Card; // Renderer: renders a single surface by id
XCard.Box
├── owns: catalogMap, surfaceCatalogMap
├── dispatches: commands → all XCard.Card children
├── aggregates: onAction events from all Cards
└── XCard.Card (id="surface-a")
│ ├── owns: component tree, data model, commandVersion
│ └── resolves: data bindings, triggers actions
└── XCard.Card (id="surface-b")
└── ...
interface BoxProps {
commands?: (XAgentCommand_v0_9 | XAgentCommand_v0_8)[];
/** Component names must start with an uppercase letter (React component convention) */
components?: Record<string, React.ComponentType<any>>;
onAction?: (payload: ActionPayload) => void;
children?: React.ReactNode; // Should contain XCard.Card elements
}
interface CardProps {
id: string; // surfaceId to render
}
interface ActionPayload {
name: string; // from action.event.name
surfaceId: string; // which surface triggered it
/**
* Context passed by component, with path references automatically resolved.
*
* For action.event.context fields using { path: "xxx" } format:
* - X-Card automatically resolves them to { value: "actual_value" }
* - Other properties (like label) are preserved
*
* Example input config:
* { username: { path: "/form/username", label: "用户名" } }
*
* Example resolved context:
* { username: { value: "张三", label: "用户名" } }
*/
context: Record<string, any>;
}
| If you need to... | Read first |
|---|---|
| Set up XCard.Box + XCard.Card | USAGE.md → Basic Setup |
| Send commands from agent to card | COMMANDS.md |
| Register a custom component catalog | CATALOG.md → Local Catalog |
| Bind component props to live data | DATA_BINDING.md |
| Handle user interactions / form submit | ACTIONS.md |
| Build a streaming progressive UI | USAGE.md → Streaming |
| Migrate from v0.8 to v0.9 | COMMANDS.md → v0.8 vs v0.9 |
| Look up full prop types | API.md |
XCard.Box components prop.XCard.Box, add XCard.Card per surface.XAgentCommand_v0_9[] into commands prop (typically from streaming agent response).ActionPayload in onAction, update commands in response.import React, { useState } from 'react';
import { XCard, registerCatalog } from '@ant-design/x-card';
import type { XAgentCommand_v0_9, ActionPayload, Catalog } from '@ant-design/x-card';
// 1. Define and register local catalog
const myCatalog: Catalog = {
catalogId: 'local://my_catalog.json',
components: {
Text: {
type: 'object',
properties: { text: { type: 'string' }, variant: { type: 'string' } },
required: ['text'],
},
Button: {
type: 'object',
properties: { text: { type: 'string' }, action: {} },
required: ['text'],
},
},
};
registerCatalog(myCatalog);
// 2. Custom component implementations
const Text: React.FC<{ text: string; variant?: string }> = ({ text, variant }) => (
<p className={`text-${variant ?? 'body'}`}>{text}</p>
);
const Button: React.FC<{ text: string; onAction?: (ctx: any) => void; action?: any }> = ({
text,
onAction,
action,
}) => <button onClick={() => onAction?.(action?.event?.context ?? {})}>{text}</button>;
// 3. Build commands (from agent stream)
const commands: XAgentCommand_v0_9[] = [
{
version: 'v0.9',
createSurface: {
surfaceId: 'welcome',
catalogId: 'local://my_catalog.json',
},
},
{
version: 'v0.9',
updateComponents: {
surfaceId: 'welcome',
components: [
{ id: 'root', component: 'Column', children: ['title', 'btn'] },
{ id: 'title', component: 'Text', text: { path: '/user/name' }, variant: 'h1' },
{
id: 'btn',
component: 'Button',
text: 'Start',
action: { event: { name: 'start', context: {} } },
},
],
},
},
{
version: 'v0.9',
updateDataModel: {
surfaceId: 'welcome',
path: '/user/name',
value: 'Alice',
},
},
];
// 4. Render
export default function App() {
const [cmdQueue, setCmdQueue] = useState<XAgentCommand_v0_9[]>(commands);
const handleAction = (payload: ActionPayload) => {
console.log('Action:', payload.name, payload.context);
// Append new commands based on agent response
setCmdQueue((prev) => [...prev /* new commands */]);
};
return (
<XCard.Box commands={cmdQueue} components={{ Text, Button }} onAction={handleAction}>
<XCard.Card id="welcome" />
</XCard.Box>
);
}
"version": "v0.9" on every command — omitting it causes protocol rejection.id: "root" component per surface's component tree — this is the tree root.id string.updateComponents for layout, updateDataModel for content/state.registerCatalog() before the component tree renders.components map to XCard.Box, not to XCard.Card — Box distributes to all Cards.components object inline — keep it stable with useMemo or module-level constant to avoid re-renders.value: { path: "..." } for two-way binding — literal values do not update the data model.action.event.context paths are write targets — they point to where user-entered data lives in the data model; do not resolve them as read sources.{ path: "xxx" } in the action config to { value: "actual_value" } in the onAction payload. This works for both v0.9 (action.event.context = { key: { path } }) and v0.8 (action.context = [{ key, value: { path } }]) formats.| Scenario | Skill combination |
|---|---|
| AI chat with structured card responses | use-x-chat + x-components + x-card |
| Standalone agent form UI | x-card only |
| Streaming Markdown + card side-panel | x-markdown + x-card |
| HTTP streaming from agent into card | x-request → feed response as commands |