---
name: "generating-flutter-ui"
description: "Generative UI (GenUI) for Flutter using AI models like Google Gemini, Anthropic Claude, or OpenAI via the genui package. Use this skill when building dynamic AI-driven interfaces, conversational UI flows, server-rendered screen layouts, LLM-powered dashboards, chat-based UI generation, or implementing prompt-to-UI systems. Supports AI-generated widgets, reactive data binding, ContentGenerator integration, and A2uiMessageProcessor for real-time UI updates from AI responses. Ideal for apps where UI structure is determined by AI/LLM output rather than hardcoded layouts."
metadata:
last_modified: "2026-04-01 14:35:00 (GMT+8)"
---
# Flutter Generative UI (GenUI) Best Practices
## Goal
Implement a dynamic user interface generated by AI using the [genui](https://pub.dev/packages/genui) package. This is the recommended approach when an application needs to build reactive screens or components directly from AI responses without hardcoding the layout.
## Instructions
The `genui` package orchestrates a conversational loop between the user, the AI (via `ContentGenerator`), and the Flutter UI (via `A2uiMessageProcessor` and `DataModel`).
### 1. Project Setup
Add the necessary packages to your `pubspec.yaml`:
```bash
flutter pub add genui
# For Gemini integration via Firebase:
flutter pub add genui_firebase_ai
```
If targeting macOS/iOS, enable outbound network requests in entitlements:
```xml
com.apple.security.network.client
```
### 2. Core Integration Structure
To connect your Flutter application to the AI agent, you need to instantiate three main components:
1. **`A2uiMessageProcessor`**: Handles the UI side, translating AI messages into UI actions. Supply it with a `Catalog` of widgets the AI is allowed to use.
2. **`ContentGenerator`**: Handles communication with the AI. Supply it with system instructions and tools.
3. **`GenUiConversation`**: The facade coordinating the processor and generator.
**Example Setup in a StatefulWidget:**
```dart
import 'package:flutter/material.dart';
import 'package:genui/genui.dart';
import 'package:genui_firebase_ai/genui_firebase_ai.dart';
class GenUIPage extends StatefulWidget {
const GenUIPage({super.key});
@override
State createState() => _GenUIPageState();
}
class _GenUIPageState extends State {
late final A2uiMessageProcessor _a2uiMessageProcessor;
late final GenUiConversation _genUiConversation;
@override
void initState() {
super.initState();
// 1. Initialize Message Processor with predefined catalog widgets
_a2uiMessageProcessor = A2uiMessageProcessor(
catalogs: [CoreCatalogItems.asCatalog()],
);
// 2. Initialize Content Generator (e.g., Firebase AI / Gemini)
final contentGenerator = FirebaseAiContentGenerator(
catalog: CoreCatalogItems.asCatalog(),
systemInstruction: '''
You are an AI assistant. You must generate UI by responding with JSON
matching the provided widget schemas. Always output valid UI structures.
''',
tools: _a2uiMessageProcessor.getTools(),
);
// 3. Orchestrate the Conversation
_genUiConversation = GenUiConversation(
a2uiMessageProcessor: _a2uiMessageProcessor,
contentGenerator: contentGenerator,
// Implement your handlers for rendering generated surfaces
onSurfaceAdded: (surfaceId) { /* Handle surface creation */ },
onSurfaceDeleted: (surfaceId) { /* Handle surface deletion */ },
onTextResponse: (text) { /* Optional: show text explicitly */ },
onError: (error) { /* Handle generation errors */ },
);
}
@override
void dispose() {
_genUiConversation.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
// UI Implementation interacting with _genUiConversation.sendRequest()
return const Scaffold();
}
}
```
### 3. Data Model & Data Binding
A core philosophy of `genui` is utilizing a central `DataModel`. Widgets don't manage their own dynamic state; instead, they bind to paths within the `DataModel`.
When creating custom widgets to add to your `Catalog`, ensure they react to the data context:
```dart
// The AI will generate JSON like:
// { "Text": { "text": { "literalString": "Hello" } } }
// OR
// { "Text": { "text": { "path": "/user/welcome_message" } } }
```
* **literalString**: Static data directly from the AI.
* **path**: A reference to a location in the `DataModel`. Updates to this path automatically rebuild any widgets bound to it. Input widgets (like `TextField`) should directly update this `DataModel`.
### 4. Customizing the Catalog
To extend GenUI beyond the `CoreCatalogItems`, define your own `CatalogItem`s and provide them to both the `A2uiMessageProcessor` and the `ContentGenerator`. This tells the AI what Custom Widgets are available and what parameters they accept.
## Constraints
* **Architecture Scope**: Do not use `genui` for static screens or standard layouts. It should be reserved exclusively for features needing generative or highly dynamic, AI-driven UI presentation.
* **State Management**: Within GenUI components, prefer the unified `DataModel` reactivity over local `setState` for data shared with the AI.
* **Error Handling**: Always ensure `onError` in `GenUiConversation` is handled appropriately, as AI responses can sometimes fail parsing or violate catalog schemas.