Skip to content

A2UI Renderer Implementation Guide

This document outlines the required features for a new renderer implementation of the A2UI protocol. It is intended for developers building new renderers (e.g., for React, Flutter, iOS, etc.).

Version Notes This guide primarily describes the v0.8 message flow. v0.9 renames several messages (surfaceUpdateupdateComponents, dataModelUpdateupdateDataModel, beginRenderingcreateSurface) and uses a flatter component format. See the v0.9 specification for details.

Web Renderers: Use @a2ui/web-lib (web_core)

Section titled “Web Renderers: Use @a2ui/web-lib (web_core)”

If you’re building a renderer for the web (React, Vue, Svelte, etc.), you don’t need to implement message processing, state management, or schema validation from scratch. The @a2ui/web-lib package (web_core) provides all the framework-agnostic logic that the maintained Lit, Angular, and React renderers share.

ModuleWhat it does
MessageProcessorProcesses the A2UI JSONL stream, dispatches messages, manages surface lifecycle
SurfaceModel / SurfaceGroupModelState management for surfaces, components, and data models
DataModel / DataContextData binding resolution, path-based lookups, template list rendering
ComponentModelComponent tree state, adjacency list → tree resolution
Types & SchemasTypeScript types for all A2UI components, primitives, colors, styles, and JSON schema validation
Expression parserClient-side function evaluation (v0.9)

All three web renderers follow the same pattern — web_core handles the protocol, the renderer handles the UI:

/ Types — shared across all renderers
import type * as Types from '@a2ui/web_core/types/types';
import type * as Primitives from '@a2ui/web_core/types/primitives';
/ v0.8: Message processing and state
import { A2uiMessageProcessor } from '@a2ui/web_core/data/model-processor';
/ v0.9: Message processing, surfaces, catalogs
import { MessageProcessor } from '@a2ui/web_core/v0_9';
import { SurfaceModel } from '@a2ui/web_core/v0_9';
/ Styles and layout helpers
import * as Styles from '@a2ui/web_core/styles/index';

Your renderer only needs to:

  1. Map A2UI component types to your framework’s components (e.g., Text<p>, Button<button>)
  2. Subscribe to state changes from web_core and re-render
  3. Forward user actions back through the MessageProcessor

See the React renderer, Lit renderer, and Angular renderer for working examples of this pattern.

web_core exports both v0.8 and v0.9 APIs:

  • @a2ui/web_core/v0_8 or @a2ui/web_core (default) — stable v0.8
  • @a2ui/web_core/v0_9 — v0.9 with createSurface, custom catalogs, client-side functions
  • @a2ui/web_core/v0_9/basic_catalog — v0.9 basic catalog expression parser and built-in functions

Start with web_core Building a web renderer without web_core means reimplementing ~3,000 lines of message processing, state management, and schema validation. Unless you have a specific reason to diverge, use it.


This section details the fundamental mechanics of the A2UI protocol. A compliant renderer must implement these systems to successfully parse the server stream, manage state, and handle user interactions.

  • JSONL Stream Parsing: Implement a parser that can read a streaming response line by line, decoding each line as a distinct JSON object.
  • Message Dispatcher: Create a dispatcher to identify the message type (beginRendering, surfaceUpdate, dataModelUpdate, deleteSurface) and route it to the correct handler.
  • Surface Management:
    • Implement a data structure to manage multiple UI surfaces, each keyed by its surfaceId.
    • Handle surfaceUpdate: Add or update components in the specified surface’s component buffer.
    • Handle deleteSurface: Remove the specified surface and all its associated data and components.
  • Component Buffering (Adjacency List):
    • For each surface, maintain a component buffer (e.g., a Map<String, Component>) to store all component definitions by their id.
    • Be able to reconstruct the UI tree at render time by resolving id references in container components (children.explicitList, child, contentChild, etc.).
  • Data Model Store:
    • For each surface, maintain a separate data model store (e.g., a JSON object or a Map<String, any>).
    • Handle dataModelUpdate: Update the data model at the specified path. The contents will be in an adjacency list format (e.g., [{ "key": "name", "valueString": "Bob" }]).
  • Progressive Rendering Control:
    • Buffer all incoming surfaceUpdate and dataModelUpdate messages without rendering immediately.
    • Handle beginRendering: This message acts as the explicit signal to perform the initial render of a surface and set the root component ID.
      • Start rendering from the specified root component ID.
      • If a catalogId is provided, ensure the corresponding component catalog is used (defaulting to the standard catalog if omitted).
      • Apply any global styles (e.g., font, primaryColor) provided in this message.
  • Data Binding Resolution:
    • Implement a resolver for BoundValue objects found in component properties.
    • If only a literal* value is present (literalString, literalNumber, etc.), use it directly.
    • If only a path is present, resolve it against the surface’s data model.
    • If both path and literal* are present, first update the data model at path with the literal value, then bind the component property to that path.
  • Dynamic List Rendering:
    • For containers with a children.template, iterate over the data list found at template.dataBinding (which resolves to a list in the data model).
    • For each item in the data list, render the component specified by template.componentId, making the item’s data available for relative data binding within the template.
  • Event Handling:
    • When a user interacts with a component that has an action defined, construct a userAction payload.
    • Resolve all data bindings within the action.context against the data model.
    • Send the complete userAction object to the server’s event handling endpoint.
  • Client Capabilities Reporting:
    • In every A2A message sent to the server (as part of the metadata), include an a2uiClientCapabilities object.
    • This object should declare the component catalog your client supports via supportedCatalogIds (e.g., including the URI for the standard 0.8 catalog).
    • Optionally, if the server supports it, provide inlineCatalogs for custom, on-the-fly component definitions.
  • Error Reporting: Implement a mechanism to send an error message to the server to report any client-side errors (e.g., failed data binding, unknown component type).

To ensure a consistent user experience across platforms, A2UI defines a standard set of components. Your client should map these abstract definitions to their corresponding native UI widgets.

  • Text: Render text content. Must support data binding on text and a usageHint for styling (h1-h5, body, caption).
  • Image: Render an image from a URL. Must support fit (cover, contain, etc.) and usageHint (avatar, hero, etc.) properties.
  • Icon: Render a predefined icon from the standard set specified in the catalog.
  • Video: Render a video player for a given URL.
  • AudioPlayer: Render an audio player for a given URL, optionally with a description.
  • Divider: Render a visual separator, supporting both horizontal and vertical axes.
  • Row: Arrange children horizontally. Must support distribution (justify-content) and alignment (align-items). Children can have a weight property to control flex-grow behavior.
  • Column: Arrange children vertically. Must support distribution and alignment. Children can have a weight property to control flex-grow behavior.
  • List: Render a scrollable list of items. Must support direction (horizontal/vertical) and alignment.
  • Card: A container that visually groups its child content, typically with a border, rounded corners, and/or shadow. Has a single child.
  • Tabs: A container that displays a set of tabs. Includes tabItems, where each item has a title and a child.
  • Modal: A dialog that appears on top of the main content. It is triggered by an entryPointChild (e.g. a button) and displays the contentChild when activated.
  • Button: A clickable element that triggers a userAction. Must be able to contain a child component (typically Text or Icon) and may vary in style based on the primary boolean.
  • CheckBox: A checkbox that can be toggled, reflecting a boolean value.
  • TextField: An input field for text. Must support a label, text (value), textFieldType (shortText, longText, number, obscured, date), and validationRegexp.
  • DateTimeInput: A dedicated input for selecting a date and/or time. Must support enableDate and enableTime.
  • MultipleChoice: A component for selecting one or more options from a list (options). Must support maxAllowedSelections and bind selections to a list or single value.
  • Slider: A slider for selecting a numeric value (value) from a defined range (minValue, maxValue).