Skip to content

.NET/Blazor implementation of the A2UI (Agent‑to‑UI) protocol: agents send declarative JSON component trees; the client renders approved widgets. Works with any A2UI backend. Supports Blazor WASM + Server; includes component catalog, data binding, streaming, and samples.

License

Notifications You must be signed in to change notification settings

23min/a2ui-blazor

Repository files navigation

A2UI Blazor

A .NET implementation of Google's A2UI (Agent-to-UI) protocol for Blazor.

Agents describe UIs as declarative JSON. A2UI Blazor renders them as native Blazor components — in WebAssembly or Server mode — against any A2UI-compliant backend, in any language.

Why This Exists

Google's A2UI protocol lets AI agents generate rich, interactive UIs without sending executable code. The agent sends a component tree; the client renders it with trusted, pre-approved widgets.

Official renderers exist for Lit, Angular, and Flutter. Enterprise .NET teams building agentic applications had no first-class option — until now.

A2UI Blazor brings A2UI to the .NET ecosystem. Same protocol, same security model, native Blazor components.

What's In This Repo

Libraries (the deliverables)

Package Description
A2UI.Blazor Core renderer library. Install this in any Blazor app to render A2UI surfaces. Parses JSONL/SSE streams, manages surface state, resolves data bindings, renders 16 standard components.
A2UI.Blazor.Server Optional server-side helpers for .NET backends. Fluent builders, stream writer, ASP.NET Core middleware. Not required — the client works with any A2UI server.

Samples

Sample Purpose
samples/dotnet-server/ .NET Minimal API serving A2UI streams using A2UI.Blazor.Server
samples/python-server/ Python FastAPI server (~50 lines) proving protocol agnosticism
samples/blazor-wasm-spa/ Standalone Blazor WebAssembly SPA consuming A2UI
samples/blazor-server-app/ Blazor Server app — same library, server-side rendering

The Blazor SPA renders identically whether pointed at the Python server or the .NET server. That's the point.

Standard Component Catalog

Category Components
Display Text, Image, Icon, Divider
Layout Row, Column, Card, List, Tabs
Input Button, TextField, CheckBox, ChoicePicker, DateTimeInput, Slider
Media Video, AudioPlayer

Custom components can be registered at startup:

builder.Services.AddA2UIBlazor(registry =>
{
    registry.Register("MyWidget", typeof(MyCustomWidget));
});

Getting Started

Prerequisites

  • .NET 10 SDK
  • uv + Python 3.10+ (only for the Python server sample)

Build

git clone https://github.com/23min/a2ui-blazor.git
cd a2ui-blazor
dotnet build

Run the Samples

Option A: .NET server + Blazor WASM SPA (two terminals)

# Terminal 1 — .NET A2UI server on port 5050
dotnet run --project samples/dotnet-server

# Terminal 2 — Blazor WASM SPA (dev server)
dotnet run --project samples/blazor-wasm-spa

Option B: Python server + Blazor WASM SPA (two terminals)

# Terminal 1 — Python A2UI server on port 8000
cd samples/python-server
uv run uvicorn server:app --port 8000

# Terminal 2 — update the SPA to point at the Python server
# Edit samples/blazor-wasm-spa/wwwroot/appsettings.json:
#   "A2UIServerUrl": "http://localhost:8000"
dotnet run --project samples/blazor-wasm-spa

Option C: Blazor Server app (enterprise SSR model)

# Start the .NET A2UI server, then:
dotnet run --project samples/blazor-server-app
# Open http://localhost:5100

All three Blazor clients render the same A2UI surfaces. The Python and .NET servers serve the same agents. Mix and match freely.

Use A2UI.Blazor in Your Own App

1. Add the package:

dotnet add package A2UI.Blazor

2. Register services in Program.cs:

builder.Services.AddA2UIBlazor();

3. Add the CSS to your index.html (WASM) or _Host.cshtml (Server):

<link href="_content/A2UI.Blazor/a2ui.css" rel="stylesheet" />

4. Render a surface in any page or component:

@using A2UI.Blazor.Components

<A2UISurface SurfaceId="my-surface" OnAction="HandleAction" />

5. Connect to any A2UI endpoint and stream messages:

// In your page's OnInitializedAsync:
var response = await Http.SendAsync(
    new HttpRequestMessage(HttpMethod.Get, "https://my-agent/stream"),
    HttpCompletionOption.ResponseHeadersRead);

var stream = await response.Content.ReadAsStreamAsync();
await foreach (var message in streamReader.ReadMessagesAsync(stream))
{
    dispatcher.Dispatch(message);
}

The SurfaceManager updates automatically. The <A2UISurface> component re-renders.

Build an A2UI Server in .NET

// Program.cs
builder.Services.AddA2UIServer();
builder.Services.AddA2UIAgent<MyAgent>();

app.UseA2UIAgents();
// MyAgent.cs
public class MyAgent : IA2UIAgent
{
    public string Route => "/agents/my-agent";

    public async Task HandleAsync(A2UIStreamWriter writer, CancellationToken ct)
    {
        await writer.WriteCreateSurfaceAsync("main");

        var components = new List<Dictionary<string, object>>
        {
            new ComponentBuilder("root", "Column")
                .Children("greeting")
                .Build(),
            new ComponentBuilder("greeting", "Text")
                .Text("Hello from A2UI!")
                .UsageHint("h1")
                .Build()
        };

        await writer.WriteUpdateComponentsAsync("main", components);
    }

    public Task HandleActionAsync(A2UIStreamWriter writer,
        UserActionRequest action, CancellationToken ct)
        => Task.CompletedTask;
}

Architecture

  Agent (Python, .NET, any language)
    │
    │  A2UI JSONL/SSE stream over HTTP
    ▼
  ┌─────────────────────────────────────┐
  │           A2UI.Blazor               │
  │                                     │
  │  JsonlStreamReader → MessageDispatcher → SurfaceManager
  │                                              │
  │  ComponentRegistry ◄─── DataBindingResolver  │
  │       │                                      │
  │  ┌────▼──────────────────────────────────┐   │
  │  │    Blazor Component Catalog           │   │
  │  │    Text │ Button │ Card │ List │ ...  │   │
  │  └───────────────────────────────────────┘   │
  └─────────────────────────────────────────┘

A2UI.Blazor is the client library. It:

  1. Reads a JSONL/SSE stream from any HTTP endpoint
  2. Dispatches messages by type (createSurface, updateComponents, updateDataModel, deleteSurface)
  3. Maintains surface state (components + data model)
  4. Resolves data bindings via JSON Pointer (RFC 6901)
  5. Renders components through Blazor's DynamicComponent

A2UI.Blazor.Server is an optional companion for .NET backends. Fluent builders and ASP.NET Core middleware for producing A2UI streams.

Protocol Compliance

Targets A2UI specification v0.9.

Message Type Direction Supported
createSurface Server → Client Yes
updateComponents Server → Client Yes
updateDataModel Server → Client Yes
deleteSurface Server → Client Yes
action Client → Server Yes

Technology Stack

  • .NET 10 (current LTS)
  • Blazor (WebAssembly and Server)
  • System.Text.Json (zero third-party dependencies in the core library)
  • ASP.NET Core (server library only)

Project Structure

src/
  A2UI.Blazor/                   # Core renderer library (NuGet deliverable)
  A2UI.Blazor.Server/            # Server helpers for .NET (NuGet deliverable)

samples/
  python-server/                 # Python FastAPI A2UI server
  dotnet-server/                 # .NET Minimal API A2UI server
  blazor-wasm-spa/               # Standalone Blazor WebAssembly SPA
  blazor-server-app/             # Blazor Server app (enterprise SSR)

tests/
  A2UI.Blazor.Tests/             # bUnit component tests (273 tests)
  A2UI.Blazor.Playwright/        # Playwright E2E browser tests (46 tests)

Project Status

Under active development. Core renderer and server libraries are functional with all 17 standard components, accessibility (WCAG 2.1 AA), dark mode, local actions, optimistic updates, and validation error rendering. Four samples demonstrate the full matrix of server (Python, .NET) and client (WASM, Server) combinations. See the Roadmap and Changelog for details.

Documentation

References

License

MIT

About

.NET/Blazor implementation of the A2UI (Agent‑to‑UI) protocol: agents send declarative JSON component trees; the client renders approved widgets. Works with any A2UI backend. Supports Blazor WASM + Server; includes component catalog, data binding, streaming, and samples.

Topics

Resources

License

Contributing

Security policy

Stars

Watchers

Forks

Packages

No packages published

Contributors 2

  •  
  •