{"slug": "a2ui-protocol-how-agents-stream-layout-data-instead-of-html-to-native-ui", "title": "A2UI Protocol: How Agents Stream Layout Data Instead of HTML to Native UI Components", "summary": "A developer has introduced A2UI, an event-based protocol that lets AI agents stream schema-validated layout data—JSON events like component_add, component_update, state_sync, and stream_end—rather than HTML or JSX, which native adapters translate into React, Angular, Lit, Flutter, SwiftUI, and Jetpack Compose components without a WebView or eval(). The design confines agents to an application-defined, versioned component catalog, so invalid components or props are rejected on both the agent SDK and client sides, enforcing capability boundaries at the protocol level. The protocol targets low-latency streaming over HTTP streaming, WebSocket, or server-sent events for real-time agent interactions across web and mobile.", "body_md": "Most agent UIs stream markdown or generate HTML strings. A2UI streams layout data that native framework adapters translate into platform components. The agent emits structured events describing buttons, cards, and forms. The client renders them using React, Flutter, SwiftUI, or Jetpack Compose without a WebView or eval().\n\nThis separation creates strict capability boundaries. The agent cannot inject arbitrary code. It composes from a fixed catalog of components defined by the application. The protocol is event-based and optimized for low-latency streaming, making it viable for real-time agent interactions across web and mobile platforms.\n\nGenerative UI typically means an LLM writes JSX or HTML, then the client renders it. This works for demos but creates three production problems:\n\nA2UI solves this by treating UI as data. The agent outputs a schema-validated stream of layout primitives. The client maps those primitives to native components. The agent never sees platform-specific rendering logic. The client never executes agent-generated code.\n\nThis is the same separation used in server-driven UI frameworks like Litho or Epoxy, but extended to agent-generated content.\n\nA2UI uses an event-based protocol. The agent emits a stream of JSON events. Each event describes a UI operation: adding a component, updating state, or signaling completion.\n\n| Event Type | Purpose | Payload | \n|---|---|---|\n| `component_add` | Append a component to the layout tree | Component type, props, parent ID | \n| `component_update` | Modify existing component props | Component ID, updated props | \n| `state_sync` | Synchronize application state | State key, value | \n| `stream_end` | Signal completion of the UI stream | Optional metadata | \n\nThe agent sends these events over HTTP streaming, WebSocket, or server-sent events. The client maintains a layout tree and applies events incrementally.\n\nJSONL format (one JSON object per line):\n\n```\n{\"type\": \"component_add\", \"id\": \"card-1\", \"component\": \"Card\", \"props\": {\"title\": \"Flight Options\", \"variant\": \"elevated\"}, \"parent\": \"root\"}\n{\"type\": \"component_add\", \"id\": \"button-1\", \"component\": \"Button\", \"props\": {\"label\": \"Book Now\", \"action\": \"submit_booking\"}, \"parent\": \"card-1\"}\n{\"type\": \"stream_end\"}\n```\n\nThe client receives these events, validates them against the component catalog schema, and renders them using the native framework adapter.\n\nThe application defines a component catalog. This is a schema that lists available components and their props. The agent can only compose from this catalog. If the agent references an undefined component or passes invalid props, the client rejects the event.\n\nThis enforces capability boundaries at the protocol level. The agent cannot:\n\nThe catalog is versioned. Agents and clients negotiate protocol versions during handshake. This allows safe evolution of the component library without breaking existing agents.\n\n``` js\nconst catalog = {\n  components: {\n    Card: {\n      props: {\n        title: { type: 'string', required: true },\n        variant: { type: 'enum', values: ['flat', 'elevated'] }\n      }\n    },\n    Button: {\n      props: {\n        label: { type: 'string', required: true },\n        action: { type: 'string', required: true },\n        disabled: { type: 'boolean', default: false }\n      }\n    }\n  }\n};\n```\n\nThe agent SDK validates outgoing events against this schema before transmission. The client validates incoming events before rendering. Both sides reject invalid data.\n\nA2UI provides native adapters for React, Angular, Lit, Flutter, SwiftUI, and Jetpack Compose. Each adapter translates the protocol's layout data into platform-specific components.\n\n`component_add` and `component_update` events.\nThe adapter maintains a mapping from A2UI component names to React components. When the agent emits a `Button` component, the adapter renders the application's `<Button>` component with the provided props.\n\nFlutter's adapter works similarly but uses a `StreamBuilder` to rebuild the widget tree on each event. The adapter maintains a `WidgetTree` model that mirrors the A2UI layout tree. Each event triggers a rebuild of the affected subtree.\n\nTypeScript adapters use generated types from the catalog schema. This provides compile-time validation of component props. If the catalog defines `Button.label` as a string, the TypeScript adapter enforces that type when rendering.\n\nFlutter and Swift adapters use code generation to produce strongly typed widget builders from the catalog schema.\n\nThe protocol is optimized for low-latency streaming. Agents can emit events as soon as they decide on a component, without waiting for the full layout to be computed. This enables progressive rendering.\n\nFor example, an agent booking a flight might:\n\nEach event is independent. The client applies them incrementally. The user sees the UI build up in real time, rather than waiting for a full page load.\n\nThe protocol supports backpressure. If the client cannot keep up with the event stream, it signals the agent to slow down. This prevents memory exhaustion on mobile devices or slow networks.\n\nThe agent SDK exposes a `canSend()` method that checks the client's readiness before emitting the next event.\n\nA2UI separates layout state from application state. Layout state is the component tree. Application state is the data the agent and client share (user selections, form inputs, API responses).\n\nThe `state_sync` event synchronizes application state. When the user selects a flight, the client sends a `state_sync` event to the agent. The agent updates its internal state and may emit new layout events in response.\n\nThis separation allows the agent to reason about state changes without re-rendering the entire UI. Only the affected components update.\n\nA2UI integrates with LangGraph for multi-step agent workflows. A LangGraph agent can emit A2UI events at each workflow step, building up the UI as the workflow progresses.\n\nFor example, a customer support agent might:\n\nEach step emits A2UI events. The client renders them incrementally. The user sees a cohesive flow without page transitions.\n\nMCP (Model Context Protocol) integration allows A2UI agents to call external tools and render the results. An agent might call a weather API via MCP, then emit a `WeatherCard` component with the response data.\n\nThe protocol is self-describing. Each event includes metadata: timestamp, agent ID, session ID. Clients can log the event stream for replay and debugging.\n\nThe A2UI Composer tool ([https://a2ui-project.github.io/composer/](https://a2ui-project.github.io/composer/)) allows developers to:\n\nThis is critical for debugging agent behavior. Instead of inspecting generated code, you inspect the event stream. You can replay a session, modify events, and see how the UI changes.\n\n| Failure | Cause | Mitigation | \n|---|---|---|\n| Invalid component reference | Agent emits unknown component name | Client rejects event, logs error, agent retries with fallback | \n| Schema validation failure | Agent sends props that violate catalog schema | Client rejects event, agent receives error response, adjusts output | \n| Stream interruption | Network failure or agent crash | Client displays last known good state, retries connection | \n| Backpressure overflow | Agent emits events faster than client can render | Client buffers events, signals backpressure, agent slows down | \n| Version mismatch | Agent uses newer catalog than client supports | Handshake fails, client requests compatible version or rejects connection | \n\nThe protocol is designed for graceful degradation. If the agent emits an invalid event, the client rejects it but continues processing subsequent events. The UI remains functional even if parts of the layout fail to render.\n\nA2UI agents typically run server-side. The client connects via HTTP streaming or WebSocket. This allows:\n\nFor offline scenarios, the agent can run on-device using a lightweight model. The catalog is bundled with the app. The protocol remains the same, but the transport is in-process rather than over the network.\n\nEach client session maintains a persistent connection to the agent. This requires connection pooling and load balancing. WebSocket connections are stateful, so sticky sessions or session affinity is required.\n\nFor high-scale deployments, consider:\n\nUse A2UI when you need strict capability boundaries for agent-generated UIs, or when the same agent must target multiple platforms (web, iOS, Android). The protocol's separation of layout data from rendering logic makes it safer than code generation and more portable than framework-specific solutions.\n\nAvoid A2UI if your UI is static or if you already have a working server-driven UI framework. The protocol adds complexity: you must define and version a component catalog, implement framework adapters, and manage event streaming. For simple chat interfaces or markdown-based agents, the overhead is not justified.\n\nA2UI shines when agents compose complex, multi-step UIs that must render natively across platforms. The 17,000+ stars and production adapters for six frameworks suggest real adoption beyond experimentation.", "url": "https://wpnews.pro/news/a2ui-protocol-how-agents-stream-layout-data-instead-of-html-to-native-ui", "canonical_source": "https://dev.to/mech_app_ai/a2ui-protocol-how-agents-stream-layout-data-instead-of-html-to-native-ui-components-1e0g", "published_at": "2026-11-15 10:07:50+00:00", "updated_at": "2026-11-15 10:20:48.353155+00:00", "lang": "en", "topics": ["ai-agents", "agent-protocols", "developer-tools", "ai-tools", "generative-ai"], "entities": ["A2UI", "React", "Angular", "Lit", "Flutter", "SwiftUI", "Jetpack Compose", "Litho"], "also_reported_by": [], "alternates": {"html": "https://wpnews.pro/news/a2ui-protocol-how-agents-stream-layout-data-instead-of-html-to-native-ui", "markdown": "https://wpnews.pro/news/a2ui-protocol-how-agents-stream-layout-data-instead-of-html-to-native-ui.md", "text": "https://wpnews.pro/news/a2ui-protocol-how-agents-stream-layout-data-instead-of-html-to-native-ui.txt", "jsonld": "https://wpnews.pro/news/a2ui-protocol-how-agents-stream-layout-data-instead-of-html-to-native-ui.jsonld"}}