diff --git a/docs/en/learn/a2ui.mdx b/docs/en/learn/a2ui.mdx
new file mode 100644
index 000000000..1d5e6b9f9
--- /dev/null
+++ b/docs/en/learn/a2ui.mdx
@@ -0,0 +1,344 @@
+---
+title: Agent-to-UI (A2UI) Protocol
+description: Enable agents to generate declarative UI surfaces for rich client rendering via the A2UI extension.
+icon: window-restore
+mode: "wide"
+---
+
+## A2UI Overview
+
+A2UI is a declarative UI protocol extension for [A2A](/en/learn/a2a-agent-delegation) that lets agents emit structured JSON messages describing interactive surfaces. Clients receive these messages and render them as rich UI components — forms, cards, lists, modals, and more — without the agent needing to know anything about the client's rendering stack.
+
+A2UI is built on the A2A extension mechanism and identified by the URI `https://a2ui.org/a2a-extension/a2ui/v0.8`.
+
+
+ A2UI requires the `a2a-sdk` package. Install with: `uv add 'crewai[a2a]'` or `pip install 'crewai[a2a]'`
+
+
+## How It Works
+
+1. The **server extension** scans agent output for A2UI JSON objects
+2. Valid messages are wrapped as `DataPart` entries with the `application/json+a2ui` MIME type
+3. The **client extension** augments the agent's system prompt with A2UI instructions and the component catalog
+4. The client tracks surface state (active surfaces and data models) across conversation turns
+
+## Server Setup
+
+Add `A2UIServerExtension` to your `A2AServerConfig` to enable A2UI output:
+
+```python Code
+from crewai import Agent
+from crewai.a2a import A2AServerConfig
+from crewai.a2a.extensions.a2ui import A2UIServerExtension
+
+agent = Agent(
+ role="Dashboard Agent",
+ goal="Present data through interactive UI surfaces",
+ backstory="Expert at building clear, actionable dashboards",
+ llm="gpt-4o",
+ a2a=A2AServerConfig(
+ url="https://your-server.com",
+ extensions=[A2UIServerExtension()],
+ ),
+)
+```
+
+### Server Extension Options
+
+
+ Component catalog identifiers the server supports. When set, only these catalogs are advertised to clients.
+
+
+
+ Whether to accept inline catalog definitions from clients in addition to named catalogs.
+
+
+## Client Setup
+
+Add `A2UIClientExtension` to your `A2AClientConfig` to enable A2UI rendering:
+
+```python Code
+from crewai import Agent
+from crewai.a2a import A2AClientConfig
+from crewai.a2a.extensions.a2ui import A2UIClientExtension
+
+agent = Agent(
+ role="UI Coordinator",
+ goal="Coordinate tasks and render agent responses as rich UI",
+ backstory="Expert at presenting agent output in interactive formats",
+ llm="gpt-4o",
+ a2a=A2AClientConfig(
+ endpoint="https://dashboard-agent.example.com/.well-known/agent-card.json",
+ extensions=[A2UIClientExtension()],
+ ),
+)
+```
+
+### Client Extension Options
+
+
+ Preferred component catalog identifier. Defaults to `"standard (v0.8)"` when not set.
+
+
+
+ Restrict which components the agent may use. When `None`, all 18 standard catalog components are available.
+
+
+## Message Types
+
+A2UI defines four server-to-client message types. Each message targets a **surface** identified by `surfaceId`.
+
+
+
+ Initializes a new surface with a root component and optional styles.
+
+ ```json
+ {
+ "beginRendering": {
+ "surfaceId": "dashboard-1",
+ "root": "main-column",
+ "catalogId": "standard (v0.8)",
+ "styles": {
+ "primaryColor": "#EB6658"
+ }
+ }
+ }
+ ```
+
+
+
+ Sends or updates one or more components on an existing surface.
+
+ ```json
+ {
+ "surfaceUpdate": {
+ "surfaceId": "dashboard-1",
+ "components": [
+ {
+ "id": "main-column",
+ "component": {
+ "Column": {
+ "children": { "explicitList": ["title", "content"] },
+ "alignment": "start"
+ }
+ }
+ },
+ {
+ "id": "title",
+ "component": {
+ "Text": {
+ "text": { "literalString": "Dashboard" },
+ "usageHint": "h1"
+ }
+ }
+ }
+ ]
+ }
+ }
+ ```
+
+
+
+ Updates the data model bound to a surface, enabling dynamic content.
+
+ ```json
+ {
+ "dataModelUpdate": {
+ "surfaceId": "dashboard-1",
+ "path": "/data/model",
+ "contents": [
+ {
+ "key": "userName",
+ "valueString": "Alice"
+ },
+ {
+ "key": "score",
+ "valueNumber": 42
+ }
+ ]
+ }
+ }
+ ```
+
+
+
+ Removes a surface and all its components.
+
+ ```json
+ {
+ "deleteSurface": {
+ "surfaceId": "dashboard-1"
+ }
+ }
+ ```
+
+
+
+## Component Catalog
+
+A2UI ships with 18 standard components organized into three categories:
+
+### Content
+
+| Component | Description | Required Fields |
+|-----------|-------------|-----------------|
+| **Text** | Renders text with optional heading/body hints | `text` (StringBinding) |
+| **Image** | Displays an image with fit and size options | `url` (StringBinding) |
+| **Icon** | Renders a named icon from a set of 47 icons | `name` (IconBinding) |
+| **Video** | Embeds a video player | `url` (StringBinding) |
+| **AudioPlayer** | Embeds an audio player with optional description | `url` (StringBinding) |
+
+### Layout
+
+| Component | Description | Required Fields |
+|-----------|-------------|-----------------|
+| **Row** | Horizontal flex container | `children` (ChildrenDef) |
+| **Column** | Vertical flex container | `children` (ChildrenDef) |
+| **List** | Scrollable list (vertical or horizontal) | `children` (ChildrenDef) |
+| **Card** | Elevated container for a single child | `child` (str) |
+| **Tabs** | Tabbed container | `tabItems` (list of TabItem) |
+| **Divider** | Visual separator (horizontal or vertical) | — |
+| **Modal** | Overlay triggered by an entry point | `entryPointChild`, `contentChild` (str) |
+
+### Interactive
+
+| Component | Description | Required Fields |
+|-----------|-------------|-----------------|
+| **Button** | Clickable button that triggers an action | `child` (str), `action` (Action) |
+| **CheckBox** | Boolean toggle with a label | `label` (StringBinding), `value` (BooleanBinding) |
+| **TextField** | Text input with type and validation options | `label` (StringBinding) |
+| **DateTimeInput** | Date and/or time picker | `value` (StringBinding) |
+| **MultipleChoice** | Selection from a list of options | `selections` (ArrayBinding), `options` (list) |
+| **Slider** | Numeric range slider | `value` (NumberBinding) |
+
+## Data Binding
+
+Components reference values through **bindings** rather than raw literals. This allows surfaces to update dynamically when the data model changes.
+
+There are two ways to bind a value:
+
+- **Literal values** — hardcoded directly in the component definition
+- **Path references** — point to a key in the surface's data model
+
+```json
+{
+ "surfaceUpdate": {
+ "surfaceId": "profile-1",
+ "components": [
+ {
+ "id": "greeting",
+ "component": {
+ "Text": {
+ "text": { "path": "/data/model/userName" },
+ "usageHint": "h2"
+ }
+ }
+ },
+ {
+ "id": "status",
+ "component": {
+ "Text": {
+ "text": { "literalString": "Online" },
+ "usageHint": "caption"
+ }
+ }
+ }
+ ]
+ }
+}
+```
+
+In this example, `greeting` reads the user's name from the data model (updated via `dataModelUpdate`), while `status` uses a hardcoded literal.
+
+## Handling User Actions
+
+Interactive components like `Button` trigger `userAction` events that flow back to the server. Each action includes a `name`, the originating `surfaceId` and `sourceComponentId`, and an optional `context` with key-value pairs.
+
+```json
+{
+ "userAction": {
+ "name": "submitForm",
+ "surfaceId": "form-1",
+ "sourceComponentId": "submit-btn",
+ "timestamp": "2026-03-12T10:00:00Z",
+ "context": {
+ "selectedOption": "optionA"
+ }
+ }
+}
+```
+
+Action context values can also use path bindings to send current data model values back to the server:
+
+```json
+{
+ "Button": {
+ "child": "confirm-label",
+ "action": {
+ "name": "confirm",
+ "context": [
+ {
+ "key": "currentScore",
+ "value": { "path": "/data/model/score" }
+ }
+ ]
+ }
+ }
+}
+```
+
+## Validation
+
+Use `validate_a2ui_message` to validate server-to-client messages and `validate_a2ui_event` for client-to-server events:
+
+```python Code
+from crewai.a2a.extensions.a2ui import validate_a2ui_message
+from crewai.a2a.extensions.a2ui.validator import (
+ validate_a2ui_event,
+ A2UIValidationError,
+)
+
+# Validate a server message
+try:
+ msg = validate_a2ui_message({"beginRendering": {"surfaceId": "s1", "root": "r1"}})
+except A2UIValidationError as exc:
+ print(exc.errors)
+
+# Validate a client event
+try:
+ event = validate_a2ui_event({
+ "userAction": {
+ "name": "click",
+ "surfaceId": "s1",
+ "sourceComponentId": "btn-1",
+ "timestamp": "2026-03-12T10:00:00Z",
+ }
+ })
+except A2UIValidationError as exc:
+ print(exc.errors)
+```
+
+## Best Practices
+
+
+
+ Begin with a `beginRendering` message and a single `surfaceUpdate`. Add data binding and interactivity once the basic flow works.
+
+
+
+ Prefer path bindings over literal values for content that changes. Use `dataModelUpdate` to push new values without resending the full component tree.
+
+
+
+ Use the `allowed_components` option on `A2UIClientExtension` to restrict which components the agent may emit, reducing prompt size and keeping output predictable.
+
+
+
+ Use `validate_a2ui_message` and `validate_a2ui_event` to catch malformed payloads early, especially when building custom integrations.
+
+
+
+## Learn More
+
+- [A2A Agent Delegation](/en/learn/a2a-agent-delegation) — configure agents for remote delegation via the A2A protocol
+- [A2A Protocol Documentation](https://a2a-protocol.org) — official protocol specification