Sample: Contact Form
This page embeds the Contact Card demo from the vue-renderer examples app: it renders the contact-card.json message stream through <A2UISurface>, including a profile card and an interactive edit form.
No Agent or API Key is required — you can interact with the preview directly in the docs. Click buttons to see the corresponding Action callback at the bottom of the demo.
Live Preview
Below is the live output of contact-card.json through <A2UISurface>, matching what you see when running ContactCardExample in the vue-renderer examples app:
Reproduce in Any Vue 3 Project
Follow these steps to recreate the live preview above in any Vue 3 + Vite app (same behavior as the vue-renderer examples app).
1. Install dependencies
npm install a2ui-vuepnpm add a2ui-vueRequires Vue 3.4+.
a2ui-vueships with the v0.9 default catalog and theme — no separate@a2ui/web_coreinstall needed.
2. Copy the sample JSON
Download contact-card.json into your project public/ folder:
your-vue-app/
└── public/
└── contact-card.json3. Configure index.html (icon font)
Add Material Symbols Outlined to <head> (required by Icon components in the contact card):
<link
rel="stylesheet"
href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:opsz,wght,FILL,GRAD@20..48,100..700,0..1,-50..200&icon_names=phone,mail,location_on,person"
/>4. Theme palette src/a2ui-palette.css
:root {
--n-100: #ffffff;
--n-10: #1b1b1b;
--n-0: #000000;
--p-100: #ffffff;
--p-60: #8487ea;
--p-50: #6a6dcd;
--p-40: #5154b3;
--p-30: #383b99;
--p-10: #06006c;
--p-0: #000000;
--font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
--font-family-flex: 'Outfit', var(--font-family);
}For the full palette see samples/client/gallery/src/styles.css in the repo.
5. Entry src/main.ts
import { createApp } from 'vue'
import App from './App.vue'
import { provideA2UI, DEFAULT_CATALOG, defaultTheme } from 'a2ui-vue'
import 'a2ui-vue/dist/a2ui-vue.css'
import './a2ui-palette.css'
const app = createApp(App)
provideA2UI({
app,
catalog: DEFAULT_CATALOG,
theme: defaultTheme,
})
app.mount('#app')6. Page component src/components/ContactCardDemo.vue
<script setup lang="ts">
import { computed, onMounted, onUnmounted, ref } from 'vue'
import { A2UISurface, useMessageProcessor, type A2uiMessage } from 'a2ui-vue'
const processor = useMessageProcessor()
const loading = ref(true)
const error = ref<string | null>(null)
const lastAction = ref<string | null>(null)
const surfaces = computed(() => {
void processor.version.value
return Array.from(processor.getSurfaces().keys())
})
let unsubscribe: (() => void) | null = null
onMounted(async () => {
unsubscribe = processor.onEvent(({ message, resolve }) => {
const { name, context } = message.action
lastAction.value = `${name}(${JSON.stringify(context)})`
resolve([])
})
try {
const response = await fetch('/contact-card.json')
if (!response.ok) {
error.value = `Failed to load contact-card.json: ${response.status}`
return
}
const messages = (await response.json()) as A2uiMessage[]
processor.clearSurfaces()
processor.processMessages(messages)
} catch (err) {
error.value = err instanceof Error ? err.message : String(err)
} finally {
loading.value = false
}
})
onUnmounted(() => {
unsubscribe?.()
})
</script>
<template>
<div class="a2ui-demo">
<p v-if="loading">Loading…</p>
<p v-else-if="error" class="a2ui-demo-error">{{ error }}</p>
<template v-else>
<A2UISurface
v-for="surfaceId in surfaces"
:key="surfaceId"
:surface-id="surfaceId"
/>
<p v-if="lastAction" class="a2ui-demo-action">
Last action: <code>{{ lastAction }}</code>
</p>
</template>
</div>
</template>
<style scoped>
.a2ui-demo {
padding: 20px;
background: #fafafa;
border-radius: 8px;
color-scheme: light;
color: #333;
}
.a2ui-demo-error {
color: #d32f2f;
}
.a2ui-demo-action {
margin-top: 12px;
color: #2e7d32;
}
</style>Validation hints
TextField / CheckBox validation messages (e.g. Password must be at least 8 characters) are styled as #b3261e by the catalog components. Avoid global p { color: ... } rules that override .a2ui-text-field-errors and similar classes.
7. Mount in src/App.vue
<script setup lang="ts">
import ContactCardDemo from './components/ContactCardDemo.vue'
</script>
<template>
<ContactCardDemo />
</template>Run npm run dev — the result should match the embedded preview above. Click buttons to see Action callbacks at the bottom; edit form fields to trigger validation hints.
What It Demonstrates
- Contact avatar, name, title, and other profile fields
- Phone, email, and address rows with icons
- An editable form section with button interactions and Action callbacks
Data Source
Sample data lives at packages/vue-renderer/src/examples/public/contact-card.json, shared with ContactCardExample in the examples app.
Related Links
- Contact Lookup — Full-stack demo (LLM Agent + client)
- Component Reference — Per-component API docs