Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
75 changes: 74 additions & 1 deletion docs/guides/authoring-components.md
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,11 @@ Keep these key points in mind when implementing components:

---

## 3. Registering with the Renderer (Client)
## 3. Registering with the Renderers (Client)

Register the component with your renderer so that A2UI can instantiate it when the agent sends a payload referencing it. The steps differ by renderer.

### Angular renderer

Once the component is implemented, register it in your client catalog. This maps the component name (used by agents) to the implementation class.

Expand Down Expand Up @@ -179,6 +183,75 @@ Key points for registration:
- **Lazy Loading**: Use `import()` to lazy-load the component code.
- **Input Bindings**: Use `inputBinding` to map properties from the schema to Angular inputs.

### Lit v0.9 (recommended)

With `@a2ui/lit/v0_9`, catalog registration is handled at the protocol level. Define a `Catalog` object with your components and pass it to the `MessageProcessor`. When the agent sends a `createSurface` message with a matching `catalogId`, the processor automatically resolves and binds your catalog — no client-side flags required.
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

... no client-side flags required.

I think that bit was referencing the v0.8 "enableCustomElement", but now that this shows up earlier in the document I think it doesn't make sense.


```typescript
import {z} from 'zod';
import {Catalog, MessageProcessor} from '@a2ui/web_core/v0_9';
import {basicCatalog} from '@a2ui/lit/v0_9';
import type {LitComponentApi} from '@a2ui/lit/v0_9';

// 1. Define your component's API using a Zod schema
const MyChartApi = {
name: 'MyChart',
tagName: 'my-chart', // your custom element tag
schema: z.object({
title: z.string().optional(),
data: z.array(z.object({label: z.string(), value: z.number()})),
}),
} satisfies LitComponentApi;

// 2. Create a named catalog containing your component(s)
const myCatalog = new Catalog<LitComponentApi>(
'mycompany.com:my-catalog', // must match what the agent sends in createSurface.catalogId
[MyChartApi],
);

// 3. Register it with the MessageProcessor alongside any other catalogs you support
const processor = new MessageProcessor<LitComponentApi>([basicCatalog, myCatalog]);
Comment on lines +212 to +213
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you add a "4." illustrating how the "processor" is used? I think that's the final piece of the puzzle.

```

The agent then selects your catalog by referencing its ID in the `createSurface` message:

```json
{
"version": "v0.9",
"createSurface": {
"surfaceId": "main",
"catalogId": "mycompany.com:my-catalog"
}
}
```

The `A2uiSurface` element in v0.9 receives a fully-resolved `SurfaceModel` (with catalog already bound), so custom components render automatically alongside standard ones.

### Lit v0.8 (legacy)
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm tempted to use the "tabs" widget that we have to hide the Lit v0.8 behind a tab, like we do here:

## Message Types
=== "v0.8 (Stable)"
Version 0.8 uses the following message types:
- **`surfaceUpdate`**: Define or update UI components
- **`dataModelUpdate`**: Update application state
- **`beginRendering`**: Signal the client to render
- **`deleteSurface`**: Remove a UI surface
=== "v0.9 (Draft)"
Version 0.9 uses the following message types:
- **`createSurface`**: Create a new surface and specify its catalog
- **`updateComponents`**: Add or update UI components in a surface
- **`updateDataModel`**: Update application state
- **`deleteSurface`**: Remove a UI surface
v0.9 separates surface creation from rendering — `createSurface` replaces both `beginRendering` and the implicit surface creation in `surfaceUpdate`. All messages include a `version` field.
(looks like this)

That way the page doesn't grow too tall, and you only see the things about the framework you care about; what do you think?


When using the `@a2ui/lit` renderer with the v0.8 protocol, register your custom components via the `componentRegistry`, then opt in on the `<a2ui-surface>` element by setting `enableCustomElements = true`.

```typescript
import {v0_8 as a2uiModule} from '@a2ui/lit';

// Register custom components in the component registry
// MyChartElement is your Lit component class (extends LitElement)
a2uiModule.componentRegistry.register('MyChart', MyChartElement);
Comment thread
shahabl marked this conversation as resolved.
```

Then set `enableCustomElements = true` on the surface element **before** assigning `surface` and `processor`, so the flag is active on the first render pass:

```typescript
const surfaceElement = document.querySelector('a2ui-surface');

surfaceElement.enableCustomElements = true; // must come first
surfaceElement.surfaceId = 'main';
surfaceElement.surface = surface; // the SurfaceModel instance
surfaceElement.processor = processor; // the A2uiMessageProcessor instance
```

> **Note:** Without `enableCustomElements = true`, custom components will not render even if they are properly registered, because the flag defaults to `false`.

---

## 4. Invoking from the Agent
Expand Down