flutter_ai_chat_ui
A complete, production-ready AI Chat UI Kit for Flutter.
Works with any AI backend — OpenAI, Anthropic Claude, Google Gemini, Ollama, or your own API.
✅ Streaming support — real-time chunk-by-chunk text rendering
✅ Built-in Markdown — bold, italic, code blocks, lists, headings, blockquotes
✅ Typing indicator — animated 3-dot bouncing indicator
✅ Message actions — copy, retry, star (long press to reveal)
✅ Emoji reactions — tap to react, counts shown on bubbles
✅ Multiple themes — clean, dark, WhatsApp-style, or fully custom
✅ Avatar support — initials fallback with custom colors
✅ Image messages — display images in chat
✅ System messages — centered info pills
✅ Scroll to bottom — floating button when scrolled up
✅ Zero external dependencies
Installation
dependencies:
flutter_ai_chat_ui: ^1.0.0
Quick Start
import 'package:flutter_ai_chat_ui/flutter_ai_chat_ui.dart';
class ChatPage extends StatefulWidget { ... }
class _ChatPageState extends State<ChatPage> {
final List<ChatMessage> _messages = [];
@override
Widget build(BuildContext context) {
return AiChatView(
messages: _messages,
onSend: _handleSend,
);
}
Future<void> _handleSend(String text) async {
// 1. Add user message
setState(() => _messages.add(ChatMessage.user(text)));
// 2. Create streaming AI message
final aiMsg = ChatMessage.aiStreaming();
setState(() => _messages.add(aiMsg));
// 3. Stream chunks from your AI
await for (final chunk in myAiService.stream(text)) {
aiMsg.appendChunk(chunk); // UI updates automatically!
}
// 4. Mark complete
aiMsg.finishStreaming();
}
}
With OpenAI
import 'package:dart_openai/dart_openai.dart';
Future<void> _handleSend(String text) async {
setState(() => _messages.add(ChatMessage.user(text)));
final aiMsg = ChatMessage.aiStreaming();
setState(() => _messages.add(aiMsg));
final stream = OpenAI.instance.chat.createStream(
model: 'gpt-4o',
messages: [OpenAIChatCompletionChoiceMessageModel(
role: OpenAIChatMessageRole.user,
content: [OpenAIChatCompletionChoiceMessageContentItemModel.text(text)],
)],
);
await for (final chunk in stream) {
final delta = chunk.choices.first.delta.content?.first?.text ?? '';
aiMsg.appendChunk(delta);
}
aiMsg.finishStreaming();
}
With Anthropic Claude
Future<void> _handleSend(String text) async {
setState(() => _messages.add(ChatMessage.user(text)));
final aiMsg = ChatMessage.aiStreaming();
setState(() => _messages.add(aiMsg));
final request = http.Request('POST', Uri.parse('https://api.anthropic.com/v1/messages'));
request.headers.addAll({
'x-api-key': 'YOUR_KEY',
'anthropic-version': '2023-06-01',
'content-type': 'application/json',
});
request.body = jsonEncode({
'model': 'claude-sonnet-4-20250514',
'max_tokens': 1024,
'stream': true,
'messages': [{'role': 'user', 'content': text}],
});
final response = await http.Client().send(request);
await for (final line in response.stream.transform(utf8.decoder).transform(const LineSplitter())) {
if (line.startsWith('data: ')) {
final data = jsonDecode(line.substring(6));
if (data['type'] == 'content_block_delta') {
aiMsg.appendChunk(data['delta']['text'] ?? '');
}
}
}
aiMsg.finishStreaming();
}
Message Types
ChatMessage.user('Hello!') // User text message
ChatMessage.ai('Here is my response') // AI text message (complete)
ChatMessage.aiStreaming() // AI message ready for streaming
ChatMessage.error('Something went wrong') // Error state bubble
ChatMessage.system('Chat started') // Centered info pill
ChatMessage.image(imageUrl: url, user: user) // Image message
ChatMessage.code(code: '...', language: 'dart') // Code block message
Theming
// Built-in presets
AiChatView(theme: AiChatTheme.clean())
AiChatView(theme: AiChatTheme.dark())
AiChatView(theme: AiChatTheme.whatsapp())
// Custom
AiChatView(
theme: AiChatTheme(
userBubbleColor: Colors.indigo,
userTextColor: Colors.white,
aiBubbleColor: Color(0xFFF0F0F0),
bubbleBorderRadius: 20,
showTimestamps: true,
showAiAvatar: true,
typingText: 'AI is thinking...',
reactionEmojis: ['👍', '❤️', '🔥', '😂'],
inputHint: 'Ask me anything...',
),
)
Custom Users / Avatars
final myAi = ChatUser.ai(
name: 'Aria',
avatarUrl: 'https://example.com/avatar.png',
avatarColor: Colors.deepPurple,
);
final me = ChatUser.human(
name: 'Rahul',
avatarColor: Colors.teal,
);
// Pass to messages
ChatMessage.user('Hi!', user: me)
ChatMessage.aiStreaming(user: myAi)
Reactions & Actions
Long-press any message bubble to reveal actions:
- Copy — copies text to clipboard
- Star — bookmark the message
- Retry — re-generate the AI response
- React — pick an emoji reaction
AiChatView(
onRetry: (msg) { /* regenerate response */ },
onStar: (msg) { /* save to favorites */ },
onReact: (msg, emoji) { /* handle reaction */ },
)
AiChatView Parameters
| Parameter | Type | Description |
|---|---|---|
messages |
List<ChatMessage> |
The message list to display |
onSend |
Future<void> Function(String) |
Called when user sends a message |
theme |
AiChatTheme |
Visual customization |
isLoading |
bool |
Shows typing indicator |
currentUserId |
String |
Your user's ID (for reactions) |
appBar |
PreferredSizeWidget? |
Optional AppBar |
showInputBar |
bool |
Toggle input bar |
onRetry |
void Function(ChatMessage)? |
Retry callback |
onStar |
void Function(ChatMessage)? |
Star callback |
onReact |
void Function(ChatMessage, String)? |
Reaction callback |
header |
Widget? |
Widget shown above messages |
emptyState |
Widget? |
Custom empty state widget |
autoScroll |
bool |
Auto-scroll on new messages |
License
MIT © 2026
Libraries
- flutter_ai_chat_ui
- FlutterAiChatUi — Complete AI Chat UI Kit