Skip to content

A2UI Migration Guide

This guide helps you migrate from other UI approaches to the A2UI component system.

A2UI (App-to-UI) is a declarative, platform-agnostic UI system that:

  • Renders natively on web, desktop, and mobile
  • Supports real-time streaming updates
  • Integrates with flow-based architectures
  • Enables AI-assisted UI generation

From React Components

Convert React JSX to A2UI JSON structures.

From HTML/CSS

Transform static markup to A2UI components.

From Custom JSON

Map your schema to A2UI format.

From Figma

Export Figma designs as A2UI.


<div className="p-4 bg-white rounded-lg shadow">
<h2 className="text-xl font-bold">{title}</h2>
<p className="text-gray-600">{description}</p>
<button onClick={handleClick}>
Click me
</button>
</div>

| React | A2UI Equivalent | |-------|-----------------| | <div> | Column, Row, or Stack | | <span> | Text | | <h1>-<h6> | Text with variant prop | | <p> | Text | | <img> | Image | | <button> | Button | | <input type="text"> | TextField | | <input type="checkbox"> | Checkbox | | <input type="radio"> | RadioGroup | | <select> | Select | | <ul>/<ol> | List | | <form> | Column with form handling |

const handleSubmit = (e) => {
e.preventDefault();
submitForm(formData);
};
<form onSubmit={handleSubmit}>
<input
value={name}
onChange={(e) => setName(e.target.value)}
/>
<button type="submit">Submit</button>
</form>
{isLoading && <Spinner />}
{error && <ErrorMessage error={error} />}
{data && <DataDisplay data={data} />}
<ul>
{items.map((item) => (
<li key={item.id}>
<span>{item.name}</span>
<button onClick={() => deleteItem(item.id)}>
Delete
</button>
</li>
))}
</ul>

<div class="card">
<div class="card-header">
<img src="avatar.jpg" class="avatar">
<div class="user-info">
<h3 class="user-name">John Doe</h3>
<span class="user-role">Developer</span>
</div>
</div>
<div class="card-body">
<p>User description here...</p>
</div>
<div class="card-footer">
<button class="btn btn-primary">Follow</button>
</div>
</div>

A2UI uses Tailwind CSS classes. Common conversions:

| CSS Property | Tailwind Class | |-------------|----------------| | margin: 16px | m-4 | | padding: 24px | p-6 | | display: flex | flex | | flex-direction: column | flex-col | | justify-content: space-between | justify-between | | align-items: center | items-center | | gap: 8px | gap-2 | | border-radius: 8px | rounded-lg | | font-size: 18px | text-lg | | font-weight: bold | font-bold | | color: #gray | text-gray-500 | | background: white | bg-white |


A2UI uses a data path system instead of component state:

const [count, setCount] = useState(0);
<button onClick={() => setCount(c => c + 1)}>
Count: {count}
</button>
const [form, setForm] = useState({
email: '',
password: ''
});
<input
type="email"
value={form.email}
onChange={(e) => setForm({
...form,
email: e.target.value
})}
/>

  1. Audit Your Components

    List all components that need migration. Prioritize:

    • High-usage components
    • Simple, self-contained components
    • Components without complex state
  2. Map Data Requirements

    Document what data each component needs:

    • Props received from parents
    • Internal state
    • External data (API, context)
  3. Design Data Paths

    Create a data path schema:

    /user/name
    /user/email
    /form/email
    /form/password
    /ui/isModalOpen
    /items/0/name
  4. Convert Components

    Start with leaf components (no children), then work up:

    • Convert structure to A2UI JSON
    • Map CSS/styles to Tailwind classes
    • Replace event handlers with actions
    • Add data bindings
  5. Set Up Actions

    Map interactions to A2UI actions:

    • Click handlers → onClick actions
    • Form changes → onChange with update
    • Submissions → submit actions
    • Navigation → navigate actions
  6. Test and Validate

    • Verify visual appearance matches
    • Test all interactions
    • Check responsive behavior
    • Validate data flows correctly

const [isOpen, setIsOpen] = useState(false);
<button onClick={() => setIsOpen(true)}>Open</button>
<Modal open={isOpen} onClose={() => setIsOpen(false)}>
<ModalContent>...</ModalContent>
</Modal>
const [activeTab, setActiveTab] = useState('tab1');
<Tabs value={activeTab} onChange={setActiveTab}>
<Tab value="tab1">Tab 1</Tab>
<Tab value="tab2">Tab 2</Tab>
</Tabs>
<TabPanel value="tab1">Content 1</TabPanel>
<TabPanel value="tab2">Content 2</TabPanel>