docs/guides/renderer-development.md
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.).
!!! info "Version Notes"
This guide primarily describes the v0.8 message flow. v0.9 renames several messages (surfaceUpdate → updateComponents, dataModelUpdate → updateDataModel, beginRendering → createSurface) and uses a flatter component format. See the v0.9 specification for details.
@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.
web_core provides| Module | What it does |
|---|---|
MessageProcessor | Processes the A2UI JSONL stream, dispatches messages, manages surface lifecycle |
SurfaceModel / SurfaceGroupModel | State management for surfaces, components, and data models |
DataModel / DataContext | Data binding resolution, path-based lookups, template list rendering |
ComponentModel | Component tree state, adjacency list → tree resolution |
| Types & Schemas | TypeScript types for all A2UI components, primitives, colors, styles, and JSON schema validation |
| Expression parser | Client-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:
Text → <p>, Button → <button>)web_core and re-renderMessageProcessorSee 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!!! tip "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.
beginRendering, surfaceUpdate, dataModelUpdate, deleteSurface) and route it to the correct handler.surfaceId.surfaceUpdate: Add or update components in the specified surface's component buffer.deleteSurface: Remove the specified surface and all its associated data and components.Map<String, Component>) to store all component definitions by their id.id references in container components (children.explicitList, child, contentChild, etc.).Map<String, any>).dataModelUpdate: Update the data model at the specified path. The contents will be in an adjacency list format (e.g., [{ "key": "name", "valueString": "Bob" }]).surfaceUpdate and dataModelUpdate messages without rendering immediately.beginRendering: This message acts as the explicit signal to perform the initial render of a surface and set the root component ID.
root component ID.catalogId is provided, ensure the corresponding component catalog is used (defaulting to the standard catalog if omitted).styles (e.g., font, primaryColor) provided in this message.BoundValue objects found in component properties.literal* value is present (literalString, literalNumber, etc.), use it directly.path is present, resolve it against the surface's data model.path and literal* are present, first update the data model at path with the literal value, then bind the component property to that path.children.template, iterate over the data list found at template.dataBinding (which resolves to a list in the data model).template.componentId, making the item's data available for relative data binding within the template.action defined, construct a userAction payload.action.context against the data model.userAction object to the server's event handling endpoint.a2uiClientCapabilities object.supportedCatalogIds (e.g., including the URI for the standard 0.8 catalog).inlineCatalogs for custom, on-the-fly component definitions.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 and a usageHint for styling (h1-h5, body, caption).fit (cover, contain, etc.) and usageHint (avatar, hero, etc.) properties.horizontal and vertical axes.distribution (justify-content) and alignment (align-items). Children can have a weight property to control flex-grow behavior.distribution and alignment. Children can have a weight property to control flex-grow behavior.direction (horizontal/vertical) and alignment.child.tabItems, where each item has a title and a child.entryPointChild (e.g. a button) and displays the contentChild when activated.userAction. Must be able to contain a child component (typically Text or Icon) and may vary in style based on the primary boolean.label, text (value), textFieldType (shortText, longText, number, obscured, date), and validationRegexp.enableDate and enableTime.options). Must support maxAllowedSelections and bind selections to a list or single value.value) from a defined range (minValue, maxValue).