Skip to content
Material 3 Expressivev1.2.2

A2UI for React

Render Google A2UI with Material 3 Expressive.

Material 3 Expressive for A2UI is a React renderer for Google’s A2UI protocol. It maps every component of the A2UI basic catalog to Google’s Material 3 Expressive design system, so the interfaces your agents generate share one theme with the rest of your app.

Stream surfaces as messages arrive, bind inputs to the data model, validate with checks, and send actions back to the agent.

Try it here

Stream an agent surface.

Scripted demo. No LLM or API key required.

Choose a scenario

Every message is scripted. You can stop playback at any time.

Streaming a surface

The agent names the card before it sends the content, so a placeholder appears first. Data bindings, formatting functions, and a later value update fill it in.

Show me my trip to Lisbon.

Play the scenario to stream the surface.

How it works

From a message stream to Material components.

The renderer sits between Google’s protocol runtime and the design system. It adds no runtime dependencies and no transport.

  1. Messages arrive

    Your agent streams A2UI JSON messages over A2A, HTTP, or a WebSocket. You parse each line and pass it to processMessages.

  2. web_core keeps the models

    Google’s @a2ui/web_core validates every message, owns the surface and data models, and evaluates bindings and catalog functions.

  3. Surfaces render

    A2uiSurface subscribes to each component and renders it with a Material 3 Expressive component. Children named before they arrive show as placeholders.

  4. Actions go back

    Inputs write into the data model. A button dispatches its event with the resolved context to your onAction callback, ready to send to the agent.

Supported components

The whole A2UI basic catalog.

All 18 components of the v0.9.1 basic catalog render with Material 3 Expressive components and tokens. Every color, type style, corner, and motion value follows your theme in light and dark modes.

A2UI componentRenders asNotes
TextTexth1 to h5 map to headline and title roles. Markdown subset: bold, italic, code, links, headings, lists.
ImageImage with variant sizingicon, avatar, smallFeature, mediumFeature, largeFeature, header.
IconIconCatalog names render as embedded glyphs. No icon font required.
VideoNative video playerControls enabled.
AudioPlayerNative audio playerControls enabled.
RowFlex rowjustify, align, and child weight.
ColumnFlex columnjustify, align, and child weight.
ListListVertical or horizontal, static children or a template.
CardCardOutlined, passive container.
TabsTabsKeyboard operable.
ModalDialogThe trigger opens the dialog and still dispatches its action.
DividerDividerHorizontal or vertical.
ButtonButtonprimary filled, default tonal, borderless text. Disabled while checks fail.
TextFieldTextField or TextAreashortText, longText, obscured, number.
CheckBoxCheckboxLabeled.
ChoicePickerRadio, Checkbox, or filter ChipExclusive or multiple, optional filter field.
SliderSliderDecimal precision follows the range.
DateTimeInputNative date and time inputMaterial tokens. ISO 8601 both ways, zone aware.
Read the component and rendering rules

Compatibility

Versions and limits.

The package is an independent community implementation. It is not affiliated with Google. A2UI and Material Design are Google projects.

Supported versions
A2UI protocolv0.9.1 (v0.9 accepted). The basic catalog.
@a2ui/web_core^0.10.7, tested with 0.10.7.
@language-lit/material3-expressive^1.2.0.
React and React DOM18 or 19.
@a2ui/reactThe catalog is tested under 0.11.0. Not a dependency; it needs React 19 itself.

Known limits

  • The basic catalog only, by default. Register other catalogs with createMaterial3Catalog.
  • Icon names outside the catalog fall back to a Material Symbols ligature, which needs that font.
  • The Markdown subset has no tables, images, raw HTML, or nested lists.
  • DateTimeInput uses the platform picker until the design system ships one.
  • primaryColor from the agent is exposed as a custom property. It does not re-theme the surface.
  • Transport, authentication, persistence, and orchestration stay in your application.

Start building

Add A2UI to your React app.

Install the renderer and its peers in a React 18 or 19 app.

npm install @language-lit/material3-expressive-a2ui @language-lit/material3-expressive @a2ui/web_core

Import both stylesheets in this order, then own a processor with useA2ui and render each surface inside your Material3Provider.

import '@language-lit/material3-expressive/styles.css'
import '@language-lit/material3-expressive-a2ui/styles.css'
import { Material3Provider } from '@language-lit/material3-expressive'
import { A2uiSurface, useA2ui } from '@language-lit/material3-expressive-a2ui'

export function AgentPanel({ send }) {
  const { surfaces, processMessages } = useA2ui({
    onAction: (action) => send(action),
  })
  // Call processMessages(messages) with each batch your agent delivers.
  return (
    <Material3Provider>
      {surfaces.map((surface) => (
        <A2uiSurface key={surface.id} surface={surface} />
      ))}
    </Material3Provider>
  )
}

Already rendering with Google’s React surface?

material3Catalog from @language-lit/material3-expressive-a2ui is a web_core catalog in the render-only shape that @a2ui/react consumes. Register it with your existing processor and keep your own surface, transport, and fallback policy.

Read how to register the catalog

Build your own agent surfaces.

Start with the setup guide, then read how each component renders and how to extend the catalog. The protocol itself is documented by the A2UI project.

Getting started with A2UI

Install the renderer, stream A2UI messages into surfaces, and send actions back to the agent.

A2UI components and rendering rules

How each basic-catalog component renders, plus binding, validation, templates, theming, and catalog extension.