Generate interfaces through a validated component catalog
How to study this lesson
Read one section, trace the worked example, and try the knowledge check. Bookmark saves a shortcut; notes appear in My notebook. Mark lesson complete is your own assessment and does not mark its lab passed.
By the end, you can
- Explain A2UI as declarative UI content rather than arbitrary executable code.
- Separate surface structure from bound application data.
- Pin current and candidate specification versions explicitly.
An interface description is a constrained proposal
An agent can choose a useful interface for the current task without generating unrestricted application code. A declarative format describes components, relationships, data bindings, and actions, while the host application supplies trusted implementations. For an incident review, the agent might request a heading, evidence table, filter, and approval button from an approved catalog. The host decides how those components look and behave on the device.
This creates a useful division of responsibility. The agent selects content and composition; the renderer validates the description and instantiates known components. Validation must cover more than whether the JSON parses. Unknown components, invalid references, excessive nesting, unsupported actions, and unsafe resource locations can all produce a bad interface from syntactically valid JSON. Treat generated UI as input to a constrained interpreter, with clear rejection and fallback behavior.
Keep A2UI versions distinct
As inspected on September 7, 2026, A2UI labels v0.9.1 as its current production release and v1.0 as a candidate. The current family describes surface creation, component updates, data model updates, and surface deletion through createSurface, updateComponents, updateDataModel, and deleteSurface. [A2UI v0.9.1 specification](https://a2ui.org/specification/v0.9.1-a2ui/). The v1.0 candidate adds changes including action identifiers, actionResponse, and surfaceProperties; do not silently mix these with an older renderer contract. [A2UI v1.0 candidate](https://a2ui.org/specification/v1.0-a2ui/).
Pin a protocol version and a compatible catalog together. A renderer supporting a component name does not necessarily support every property that a newer catalog defines. Include schema validation in the integration boundary and keep migration fixtures. The examples in this module use an intentionally smaller local schema, clearly labeled as a teaching simulation rather than a conforming A2UI renderer.
Structure and data have different jobs
A component graph describes what exists in the interface: a title, a row, a button, or a chart region. A data model contains changing values such as the selected incident, its status, and the proposed action. Binding the status label to a data path lets the host update content without rebuilding the entire component graph. Stable component identifiers help preserve focus and local interaction state across updates.
Suppose a user edits an incident title while the agent refreshes the evidence list. Replacing the whole interface can reset the text cursor or overwrite the unfinished edit. A better design updates the evidence data while preserving the editor component and its local draft. The exact binding and synchronization semantics depend on the selected protocol and renderer, but the architectural concern is general: changing data should not accidentally destroy user interaction state that the agent did not intend to modify.
A catalog is also a boundary on behavior
A catalog can allow Text, Table, and Button while excluding arbitrary Script or unrestricted HTML. A button action should refer to a known application action with validated parameters. A generated label saying approve does not create authority to execute the underlying operation. The server must verify the user session, proposal identity, current revision, and permission when the action returns.
Resource references need similar care. An image component may contain a URL, but the host should enforce its resource policy and avoid treating a catalog identifier as permission to download executable code from any origin. Limit component count and depth to protect renderer performance. Make errors visible to the generation loop in a structured way, such as unknown component at node seven, so correction is bounded and specific instead of repeatedly asking the model to regenerate an entire interface.
Evaluate usefulness as well as validity
A schema-valid interface can still be unusable. It might hide the critical amount below several panels, use ambiguous action labels, omit a cancel path, or reorder controls while a user is interacting. Evaluate whether the generated interface helps the user make the intended decision. For an approval surface, the target, proposed change, relevant evidence, and consequence should be available before the user acts.
Build fixtures for a valid minimal surface, an unknown component, a missing referenced child, a too-large list, and a stale action. Check keyboard access and accessible naming in the actual host renderer. The lesson code validates a tiny catalog and produces a text preview; it cannot test a graphical renderer's accessibility or layout. Its purpose is to make the content-versus-execution boundary concrete before you add a versioned A2UI integration and a real frontend component library.
Work through the code
This teaching simulation validates a tiny local component schema, not A2UI wire messages or a full catalog. It checks allowed component and action names, then prints validation results. Production validation must also enforce property types, graph references, resource policy, and the pinned official schema.
CATALOG = {'Text': {'text'}, 'Button': {'label', 'action'}}
ACTIONS = {'review_proposal'}
def validate(component):
kind = component['kind']
if kind not in CATALOG:
raise ValueError('unknown component')
props = component['props']
if set(props) != CATALOG[kind]:
raise ValueError('invalid properties')
if kind == 'Button' and props['action'] not in ACTIONS:
raise ValueError('unknown action')
return True
surface = [
{'kind': 'Text', 'props': {'text': 'Review incident 17'}},
{'kind': 'Button', 'props': {'label': 'Review proposal',
'action': 'review_proposal'}},
]
for component in surface:
print(component['kind'], validate(component))
print('execution: host-defined actions only')
Text True Button True execution: host-defined actions only
Run Python snippets locally with the prerequisites named above. The module coding lab runs directly in your browser.
Pause and reason
A generated surface contains an unknown ChartScript component but otherwise valid JSON. How should the host handle it?
Check your understanding
What is the main purpose of separating component structure from data?
Your notes
Explain the mechanism in your own words. Add a failure you want to test.