Tutorial12 min read

Getting Started with A2UI: Your First Component

Step-by-step tutorial to create your first A2UI component. Understand the JSON structure and rendering process.

A2

A2UI.sh Team

Community Contributors

Prerequisites

Before diving into A2UI, you should have:

  • Basic understanding of JSON
  • Familiarity with UI component concepts (buttons, forms, inputs)
  • Optional: Experience with web development (helpful but not required)

If you haven't already, read our Introduction to A2UI to understand the core concepts.

Understanding A2UI Components

Every A2UI component is defined as a JSON object with these key properties:

  • type — The component type from the approved catalog (e.g., "a2ui.Button")
  • id — A unique identifier for this component instance
  • props — Configuration options specific to the component type
  • children — (Optional) Array of child component IDs
  • events — (Optional) Event handlers for user interactions

Here's the simplest possible A2UI component — a button:

JSON
{
  "type": "a2ui.Button",
  "id": "my-button",
  "props": {
    "label": "Click Me",
    "variant": "primary"
  }
}

The Adjacency List Format

Unlike traditional nested JSON, A2UI uses a flat adjacency list. Instead of nesting children inside parents, each component is a separate object, and parent-child relationships are expressed through ID references.

This design has several benefits:

  • LLM-friendly: Easier for language models to generate correctly
  • Streaming support: Components can be sent and rendered incrementally
  • Validation: Each component can be validated independently
  • Flexibility: Components can be referenced by multiple parents (shared components)

Your First A2UI Message

Let's build something practical: a contact form with name and email inputs. Here's the complete A2UI message:

contact-form.json
[
  {
    "type": "a2ui.Form",
    "id": "contact-form",
    "children": ["name-input", "email-input", "submit-button"],
    "props": {
      "onSubmit": "handleContactSubmit"
    }
  },
  {
    "type": "a2ui.TextInput",
    "id": "name-input",
    "props": {
      "label": "Your Name",
      "placeholder": "Enter your name",
      "required": true
    }
  },
  {
    "type": "a2ui.TextInput",
    "id": "email-input",
    "props": {
      "label": "Email Address",
      "placeholder": "you@example.com",
      "type": "email",
      "required": true
    }
  },
  {
    "type": "a2ui.Button",
    "id": "submit-button",
    "props": {
      "label": "Send Message",
      "variant": "primary",
      "type": "submit"
    }
  }
]

Let's break down what's happening:

  1. The a2ui.Form component defines the container and lists its children by ID
  2. Two a2ui.TextInput components provide the input fields
  3. An a2ui.Button with type: "submit" triggers form submission
  4. The onSubmit prop tells the client what action to trigger when the form is submitted

Streaming JSONL

One of A2UI's most powerful features is streaming support. Instead of waiting for the entire UI to be generated, clients can render components as they arrive:

JavaScript
// Stream 1: Container arrives
{"type": "a2ui.Container", "id": "root", "children": ["header", "list"]}

// Stream 2: Header arrives
{"type": "a2ui.Text", "id": "header", "props": {"text": "Search Results"}}

// Stream 3: List arrives (can render immediately)
{"type": "a2ui.List", "id": "list", "children": ["item-1", "item-2"]}

// Stream 4-5: Items arrive
{"type": "a2ui.ListItem", "id": "item-1", "props": {"title": "Result 1"}}
{"type": "a2ui.ListItem", "id": "item-2", "props": {"title": "Result 2"}}

Each line is a valid JSON object that can be parsed and rendered immediately. The client maintains a map of component IDs and updates the UI as new components arrive.

Adding Interactivity

A2UI components can define event handlers that trigger actions when users interact with them:

JSON
{
  "type": "a2ui.Button",
  "id": "action-button",
  "props": {
    "label": "Confirm Order",
    "variant": "primary"
  },
  "events": {
    "onClick": {
      "action": "agent.confirmOrder",
      "payload": {
        "orderId": "12345"
      }
    }
  }
}

When the user clicks this button, the client will:

  1. Capture the click event
  2. Look up the "onClick" handler
  3. Send the action ("agent.confirmOrder") and payload back to the agent
  4. The agent can then process the order and respond with a new UI

Best Practices

Keep Components Simple

Each component should do one thing well. If you find yourself adding too many props, consider splitting into multiple components.

Use Semantic Types

Choose component types that match your intent. Use a2ui.Button for actions, a2ui.Link for navigation, and a2ui.TextInput for data entry.

Plan for Streaming

Design your UI so that important content can be shown first. Put critical information in early components and progressive details in later ones.

Test on Multiple Renderers

If your agent will be used across platforms, test your A2UI output with different renderers to ensure consistency.

Next Steps

You now have the foundation to start building A2UI components. Here's where to go next:

Found this helpful?

Share it with others learning about A2UI.

View all articles