# A2uiSurface

## Functions summary

|---|---|
| `https://kotlinlang.org/api/core/kotlin-stdlib/kotlin/-unit/index.html` | `@https://developer.android.com/reference/kotlin/androidx/compose/runtime/Composable https://developer.android.com/reference/kotlin/androidx/compose/material3/a2ui/A2uiSurface.composable#A2uiSurface(androidx.a2ui.model.processor.A2uiSurfaceModel,androidx.compose.ui.Modifier,kotlin.Function0,kotlin.Function1,kotlin.Function1)( surfaceModel: https://developer.android.com/reference/kotlin/androidx/a2ui/model/processor/A2uiSurfaceModel, modifier: https://developer.android.com/reference/kotlin/androidx/compose/ui/Modifier, loadingContent: @https://developer.android.com/reference/kotlin/androidx/compose/runtime/Composable () -> https://kotlinlang.org/api/core/kotlin-stdlib/kotlin/-unit/index.html, errorContent: @https://developer.android.com/reference/kotlin/androidx/compose/runtime/Composable (https://developer.android.com/reference/kotlin/androidx/a2ui/model/protocol/A2uiException) -> https://kotlinlang.org/api/core/kotlin-stdlib/kotlin/-unit/index.html, transitionSpec: (https://developer.android.com/reference/kotlin/androidx/compose/animation/AnimatedContentTransitionScope<https://developer.android.com/reference/kotlin/androidx/a2ui/compose/runtime/A2uiComponentState>.() -> https://developer.android.com/reference/kotlin/androidx/compose/animation/ContentTransform)? )` Displays an A2UI surface styled with Material Design 3. |

## Functions

### A2uiSurface

Artifact: [androidx.compose.material3:material3-a2ui](https://developer.android.com/jetpack/androidx/releases/compose-material3) [View Source](https://cs.android.com/search?q=file:androidx/compose/material3/a2ui/A2uiSurface.kt+function:A2uiSurface)

```
@Composable
fun A2uiSurface(
    surfaceModel: A2uiSurfaceModel,
    modifier: Modifier = Modifier,
    loadingContent: @Composable () -> Unit = { A2uiSurfaceDefaults.LoadingIndicator() },
    errorContent: @Composable (A2uiException) -> Unit = { A2uiSurfaceDefaults.ErrorFallback(it) },
    transitionSpec: (AnimatedContentTransitionScope<A2uiComponentState>.() -> ContentTransform)? = A2uiSurfaceDefaults.transitionSpec
): Unit
```

Displays an A2UI surface styled with Material Design 3.

This composable acts as the visual root for an A2UI surface. It observes the reactive state of the root component within the provided `https://developer.android.com/reference/kotlin/androidx/compose/material3/a2ui/package-summary#A2uiSurface(androidx.a2ui.model.processor.A2uiSurfaceModel,androidx.compose.ui.Modifier,kotlin.Function0,kotlin.Function1,kotlin.Function1)` and automatically handles transitions between loading, error, and success states. It applies Material 3 design patterns for its default loading indicator, error fallback, and animated transitions between layout changes.

Note that data-only updates to the underlying `https://developer.android.com/reference/kotlin/androidx/a2ui/model/processor/A2uiSurfaceModel` (e.g., text or binding changes that do not alter the component hierarchy) do not trigger structural transition animations, ensuring high-performance reactive updates.

### Setup and Initialization

To obtain a valid `https://developer.android.com/reference/kotlin/androidx/compose/material3/a2ui/package-summary#A2uiSurface(androidx.a2ui.model.processor.A2uiSurfaceModel,androidx.compose.ui.Modifier,kotlin.Function0,kotlin.Function1,kotlin.Function1)` instance:

1. Create an `https://developer.android.com/reference/kotlin/androidx/a2ui/compose/ui/A2uiCatalog` using the `https://developer.android.com/reference/kotlin/androidx/a2ui/compose/ui/A2uiCatalog` or `https://developer.android.com/reference/kotlin/androidx/compose/material3/a2ui/catalog/package-summary#materialA2uiBasicCatalogV1(androidx.a2ui.compose.ui.catalog.A2uiBasicCatalogV1.Image,androidx.a2ui.compose.ui.catalog.A2uiBasicCatalogV1.Video,androidx.a2ui.compose.ui.catalog.A2uiBasicCatalogV1.AudioPlayer,androidx.a2ui.compose.ui.catalog.A2uiBasicCatalogV1.Functions,androidx.a2ui.compose.ui.catalog.A2uiBasicCatalogV1.Text,androidx.a2ui.compose.ui.catalog.A2uiBasicCatalogV1.Icon,androidx.a2ui.compose.ui.catalog.A2uiBasicCatalogV1.Row,androidx.a2ui.compose.ui.catalog.A2uiBasicCatalogV1.Column,androidx.a2ui.compose.ui.catalog.A2uiBasicCatalogV1.List,androidx.a2ui.compose.ui.catalog.A2uiBasicCatalogV1.Card,androidx.a2ui.compose.ui.catalog.A2uiBasicCatalogV1.Tabs,androidx.a2ui.compose.ui.catalog.A2uiBasicCatalogV1.Modal,androidx.a2ui.compose.ui.catalog.A2uiBasicCatalogV1.Divider,androidx.a2ui.compose.ui.catalog.A2uiBasicCatalogV1.Button,androidx.a2ui.compose.ui.catalog.A2uiBasicCatalogV1.TextField,androidx.a2ui.compose.ui.catalog.A2uiBasicCatalogV1.CheckBox,androidx.a2ui.compose.ui.catalog.A2uiBasicCatalogV1.ChoicePicker,androidx.a2ui.compose.ui.catalog.A2uiBasicCatalogV1.Slider,androidx.a2ui.compose.ui.catalog.A2uiBasicCatalogV1.DateTimeInput)` factory functions.

2. Create an `https://developer.android.com/reference/kotlin/androidx/a2ui/model/processor/A2uiMessageProcessor` using the `https://developer.android.com/reference/kotlin/androidx/a2ui/compose/ui/package-summary#A2uiMessageProcessor(kotlin.collections.List,kotlin.collections.List)` factory function with the catalog(s), typically hosted in a `ViewModel`.

3. Run `https://developer.android.com/reference/kotlin/androidx/a2ui/model/processor/A2uiMessageProcessor#collectMessages()` on a background coroutine dispatcher to process agent messages.

4. Collect `https://developer.android.com/reference/kotlin/androidx/a2ui/model/processor/A2uiMessageProcessor#activeSurfaces()` and pass the emitted `https://developer.android.com/reference/kotlin/androidx/a2ui/model/processor/A2uiSurfaceModel` to this composable.

For basic `https://developer.android.com/reference/kotlin/androidx/compose/material3/a2ui/A2uiSurface.composable#A2uiSurface(androidx.a2ui.model.processor.A2uiSurfaceModel,androidx.compose.ui.Modifier,kotlin.Function0,kotlin.Function1,kotlin.Function1)` usage:

```kotlin
import androidx.a2ui.compose.ui.A2uiMessageProcessor
import androidx.a2ui.compose.ui.catalog.A2uiBasicCatalogV1
import androidx.a2ui.model.protocol.A2uiComponentPayload
import androidx.a2ui.model.protocol.A2uiCreateSurfaceMessage
import androidx.a2ui.model.protocol.A2uiUpdateComponentsMessage
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.material3.a2ui.A2uiSurface
import androidx.compose.material3.a2ui.catalog.MaterialA2uiBasicCatalogV1Defaults
import androidx.compose.material3.a2ui.catalog.materialA2uiBasicCatalogV1
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext

val context = LocalContext.current
val catalog =
    remember(context) {
        materialA2uiBasicCatalogV1(
            image = MaterialA2uiBasicCatalogV1Defaults.image { _, _, _, _, _ -> },
            video = MaterialA2uiBasicCatalogV1Defaults.video { _, _, _ -> },
            audioPlayer = MaterialA2uiBasicCatalogV1Defaults.audioPlayer { _, _, _, _ -> },
            functions = A2uiBasicCatalogV1.Functions(context),
        )
    }
// Note: The message processor should typically be hosted in a ViewModel.
val processor = remember(catalog) { A2uiMessageProcessor(catalogs = listOf(catalog)) }

LaunchedEffect(processor) {
    // Note: Message collection should typically be run on a background thread.
    launch(Dispatchers.Default) { processor.collectMessages() }

    val surfaceId = "surface_1"
    // Simulate payloads received from an agent to create the surface and its root component
    processor.processMessage(A2uiCreateSurfaceMessage(surfaceId, catalog.id))
    processor.processMessage(
        A2uiUpdateComponentsMessage(
            surfaceId,
            listOf(
                A2uiComponentPayload(
                    id = "root",
                    type = "Text",
                    properties = mapOf("text" to "Hello, A2UI with Material 3!"),
                )
            ),
        )
    )
}

val surfaces by processor.activeSurfaces.collectAsState()
// Note: The UI is typically expected to render all active surfaces (e.g., in a list).
val surfaceModel = surfaces.firstOrNull()

if (surfaceModel != null) {
    A2uiSurface(surfaceModel = surfaceModel, modifier = Modifier.fillMaxSize())
}
```

To customize the loading indicator and error fallback content:

```kotlin
import androidx.a2ui.compose.ui.A2uiMessageProcessor
import androidx.a2ui.compose.ui.catalog.A2uiBasicCatalogV1
import androidx.a2ui.model.protocol.A2uiComponentPayload
import androidx.a2ui.model.protocol.A2uiCreateSurfaceMessage
import androidx.a2ui.model.protocol.A2uiUpdateComponentsMessage
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.LinearProgressIndicator
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.material3.a2ui.A2uiSurface
import androidx.compose.material3.a2ui.catalog.MaterialA2uiBasicCatalogV1Defaults
import androidx.compose.material3.a2ui.catalog.materialA2uiBasicCatalogV1
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.unit.dp

val context = LocalContext.current
val catalog =
    remember(context) {
        materialA2uiBasicCatalogV1(
            image = MaterialA2uiBasicCatalogV1Defaults.image { _, _, _, _, _ -> },
            video = MaterialA2uiBasicCatalogV1Defaults.video { _, _, _ -> },
            audioPlayer = MaterialA2uiBasicCatalogV1Defaults.audioPlayer { _, _, _, _ -> },
            functions = A2uiBasicCatalogV1.Functions(context),
        )
    }
// Note: The message processor should typically be hosted in a ViewModel.
val processor = remember(catalog) { A2uiMessageProcessor(catalogs = listOf(catalog)) }

LaunchedEffect(processor) {
    // Note: Message collection should typically be run on a background thread.
    launch(Dispatchers.Default) { processor.collectMessages() }

    val surfaceId = "surface_1"
    // Simulate payloads received from an agent to create the surface
    processor.processMessage(A2uiCreateSurfaceMessage(surfaceId, catalog.id))

    // Simulate network latency before components arrive so that the loading content is visible
    delay(2000.milliseconds)

    // Populate its root component
    processor.processMessage(
        A2uiUpdateComponentsMessage(
            surfaceId,
            listOf(
                A2uiComponentPayload(
                    id = "root",
                    type = "Text",
                    properties = mapOf("text" to "Hello, A2UI with Material 3!"),
                )
            ),
        )
    )
}

val surfaces by processor.activeSurfaces.collectAsState()
// Note: The UI is typically expected to render all active surfaces (e.g., in a list).
val surfaceModel = surfaces.firstOrNull()

if (surfaceModel != null) {
    A2uiSurface(
        surfaceModel = surfaceModel,
        modifier = Modifier.fillMaxSize(),
        loadingContent = {
            Box(
                modifier = Modifier.fillMaxWidth().padding(16.dp),
                contentAlignment = Alignment.Center,
            ) {
                LinearProgressIndicator(modifier = Modifier.fillMaxWidth())
            }
        },
        errorContent = { exception ->
            Surface(
                color = MaterialTheme.colorScheme.errorContainer,
                shape = MaterialTheme.shapes.medium,
                modifier = Modifier.padding(16.dp),
            ) {
                Text(
                    text = "Failed to load surface: ${exception.message}",
                    modifier = Modifier.padding(16.dp),
                )
            }
        },
    )
}
```

To customize transition animations between visual states:

```kotlin
import androidx.a2ui.compose.ui.A2uiMessageProcessor
import androidx.a2ui.compose.ui.catalog.A2uiBasicCatalogV1
import androidx.a2ui.model.protocol.A2uiComponentPayload
import androidx.a2ui.model.protocol.A2uiCreateSurfaceMessage
import androidx.a2ui.model.protocol.A2uiUpdateComponentsMessage
import androidx.compose.animation.SizeTransform
import androidx.compose.animation.core.tween
import androidx.compose.animation.fadeIn
import androidx.compose.animation.fadeOut
import androidx.compose.animation.togetherWith
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.material3.a2ui.A2uiSurface
import androidx.compose.material3.a2ui.catalog.MaterialA2uiBasicCatalogV1Defaults
import androidx.compose.material3.a2ui.catalog.materialA2uiBasicCatalogV1
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext

val context = LocalContext.current
val catalog =
    remember(context) {
        materialA2uiBasicCatalogV1(
            image = MaterialA2uiBasicCatalogV1Defaults.image { _, _, _, _, _ -> },
            video = MaterialA2uiBasicCatalogV1Defaults.video { _, _, _ -> },
            audioPlayer = MaterialA2uiBasicCatalogV1Defaults.audioPlayer { _, _, _, _ -> },
            functions = A2uiBasicCatalogV1.Functions(context),
        )
    }
// Note: The message processor should typically be hosted in a ViewModel.
val processor = remember(catalog) { A2uiMessageProcessor(catalogs = listOf(catalog)) }

LaunchedEffect(processor) {
    // Note: Message collection should typically be run on a background thread.
    launch(Dispatchers.Default) { processor.collectMessages() }

    val surfaceId = "surface_1"
    // Simulate payloads received from an agent to create the surface
    processor.processMessage(A2uiCreateSurfaceMessage(surfaceId, catalog.id))

    // Simulate network latency before components arrive to demonstrate the transition animation
    delay(2000.milliseconds)

    // Populate its root component
    processor.processMessage(
        A2uiUpdateComponentsMessage(
            surfaceId,
            listOf(
                A2uiComponentPayload(
                    id = "root",
                    type = "Text",
                    properties = mapOf("text" to "Hello, A2UI with Material 3!"),
                )
            ),
        )
    )
}

val surfaces by processor.activeSurfaces.collectAsState()
// Note: The UI is typically expected to render all active surfaces (e.g., in a list).
val surfaceModel = surfaces.firstOrNull()

if (surfaceModel != null) {
    A2uiSurface(
        surfaceModel = surfaceModel,
        modifier = Modifier.fillMaxSize(),
        transitionSpec = {
            (fadeIn(animationSpec = tween(600)) togetherWith
                    fadeOut(animationSpec = tween(600)))
                .using(SizeTransform(clip = false))
        },
    )
}
```

| Parameters |
|---|---|
| `surfaceModel: https://developer.android.com/reference/kotlin/androidx/a2ui/model/processor/A2uiSurfaceModel` | the `https://developer.android.com/reference/kotlin/androidx/a2ui/model/processor/A2uiSurfaceModel` containing the data, components, and catalog for this UI, typically obtained from `https://developer.android.com/reference/kotlin/androidx/a2ui/model/processor/A2uiMessageProcessor#activeSurfaces()` |
| `modifier: https://developer.android.com/reference/kotlin/androidx/compose/ui/Modifier = Modifier` | the `https://developer.android.com/reference/kotlin/androidx/compose/ui/Modifier` to be applied to the surface layout |
| `loadingContent: @https://developer.android.com/reference/kotlin/androidx/compose/runtime/Composable () -> https://kotlinlang.org/api/core/kotlin-stdlib/kotlin/-unit/index.html = { A2uiSurfaceDefaults.LoadingIndicator() }` | the composable to display while the root component is loading or resolving its dynamic data bindings. By default, this uses `https://developer.android.com/reference/kotlin/androidx/compose/material3/a2ui/A2uiSurfaceDefaults#LoadingIndicator()` |
| `errorContent: @https://developer.android.com/reference/kotlin/androidx/compose/runtime/Composable (https://developer.android.com/reference/kotlin/androidx/a2ui/model/protocol/A2uiException) -> https://kotlinlang.org/api/core/kotlin-stdlib/kotlin/-unit/index.html = { A2uiSurfaceDefaults.ErrorFallback(it) }` | the composable to display if the root component fails to evaluate or render due to a validation or runtime error. By default, this uses `https://developer.android.com/reference/kotlin/androidx/compose/material3/a2ui/A2uiSurfaceDefaults#ErrorFallback(androidx.a2ui.model.protocol.A2uiException)` |
| `transitionSpec: (https://developer.android.com/reference/kotlin/androidx/compose/animation/AnimatedContentTransitionScope<https://developer.android.com/reference/kotlin/androidx/a2ui/compose/runtime/A2uiComponentState>.() -> https://developer.android.com/reference/kotlin/androidx/compose/animation/ContentTransform)? = A2uiSurfaceDefaults.transitionSpec` | the `https://developer.android.com/reference/kotlin/androidx/compose/animation/ContentTransform` animation used when the root transitions between loading, error, and success states. By default, uses `https://developer.android.com/reference/kotlin/androidx/compose/material3/a2ui/A2uiSurfaceDefaults#transitionSpec()`. Set to `null` to disable animations |

| Throws |
|---|---|
| `https://kotlinlang.org/api/core/kotlin-stdlib/kotlin/-illegal-argument-exception/index.html` | if `https://developer.android.com/reference/kotlin/androidx/compose/material3/a2ui/package-summary#A2uiSurface(androidx.a2ui.model.processor.A2uiSurfaceModel,androidx.compose.ui.Modifier,kotlin.Function0,kotlin.Function1,kotlin.Function1)` does not implement `A2uiCoreSurfaceModel` (e.g., if the message processor was not created using the `https://developer.android.com/reference/kotlin/androidx/a2ui/compose/ui/package-summary#A2uiMessageProcessor(kotlin.collections.List,kotlin.collections.List)` factory function), or if its catalog does not implement `https://developer.android.com/reference/kotlin/androidx/a2ui/compose/ui/A2uiCatalog` (e.g., if the catalog was not created using the `https://developer.android.com/reference/kotlin/androidx/a2ui/compose/ui/A2uiCatalog` factory function) |