The most complete AI agent UI for React Native
Build beautiful, intelligent chat interfaces with AI agents in React Native
- π¨ Beautiful UI Components - Pre-built, customizable chat components with modern design
- π§ AI Agent Ready - Built specifically for AI agent interactions with streaming responses
- π― TypeScript Support - Full TypeScript definitions for all components and props
- π§ Highly Customizable - Extensive prop system and render functions for complete customization
- π¬ Rich Media Support - Full support for images,and files with lightbox viewing
- π§΅ Thread Management - Multi-conversation support with persistent thread history
- β¨οΈ Smart Keyboard - Intelligent keyboard handling with React Native Keyboard Controller
- π Smooth Animations - Native animations powered by React Native Reanimated 3
- π Built-in AI Tools - Native tools including todo lists, and web search
- π File Upload System - Complete file upload
- π Thinking Indicators - Beautiful animated thinking indicators for AI processing states
- π Function Calling - Full support for AI function calls with custom tool UI integration
- ποΈ Server/Client Tools - Support for both server-executed and client-side interactive tools
- π Message Streaming - Real-time streaming message updates via Server-Sent Events
npm install react-native-ajora
# or
yarn add react-native-ajoraMake sure you have these peer dependencies installed:
npm install @expo/vector-icons @expo/react-native-action-sheet react-native-keyboard-controller react-native-reanimated expo-document-picker expo-image-pickerimport React from "react";
import { SafeAreaView } from "react-native-safe-area-context";
import { Ajora, AjoraProvider } from "react-native-ajora";
const App = () => {
return (
<AjoraProvider
baseUrl="http://localhost:3000" // Your backend server URL
bearerToken="your-auth-token" // Optional authentication token
debug={true} // Optional debug mode
>
<SafeAreaView style={{ flex: 1 }}>
<Ajora
showHeader={true}
showThreads={true}
isScrollToBottomEnabled={true}
keyboardShouldPersistTaps="never"
infiniteScroll={true}
onSend={(messages) => {
console.log("New messages:", messages);
}}
onUpload={async ({ file, onProgress, onSuccess, onError }) => {
// Handle file upload with progress tracking
try {
const uploadedUrl = await uploadFile(file.fileUri, onProgress);
onSuccess(uploadedUrl);
} catch (error) {
onError(error);
}
}}
/>
</SafeAreaView>
</AjoraProvider>
);
};
export default App;The main chat component that orchestrates all other components.
const App = () => {
const onUpload = async ({
file,
onProgress,
onSuccess,
onError,
}: OnUploadProps) => {
try {
const { fileUri, displayName, mimeType } = file;
const uploadedUrl = await uploadToCloudinary(fileUri, onProgress);
onProgress?.(100, true);
onSuccess?.(uploadedUrl);
} catch (error) {
onError?.(error);
}
};
return (
<SafeAreaView style={{ flex: 1 }}>
<Ajora
isScrollToBottomEnabled
keyboardShouldPersistTaps="never"
infiniteScroll
onUpload={onUpload}
/>
</SafeAreaView>
);
};
export default App;interface IMessage {
_id: string;
thread_id: string;
role: "user" | "model";
parts: Part[];
createdAt?: string;
updatedAt?: string;
}
// Part interface from @google/genai
interface Part {
text?: string; // Text content
inlineData?: {
mimeType: string;
data: string; // Base64 encoded data
};
fileData?: {
mimeType: string;
fileUri: string;
displayName?: string;
};
functionCall?: FunctionCall; // AI tool/function call
functionResponse?: FunctionResponse; // Tool response
}
interface FunctionCall {
id?: string;
args?: Record<string, unknown>;
name?: string;
response?: any; // Merged response data
}
interface FunctionResponse {
id?: string;
name?: string;
response?: Record<string, unknown>;
}import { Thread } from "react-native-ajora";
<Ajora
showHeader={true}
showThreads={true}
onThreadSelect={(thread: Thread) => {
console.log("Selected thread:", thread);
// Thread switching is handled automatically
}}
onNewThread={() => {
console.log("Creating new thread");
// New thread creation is handled automatically
}}
onHeaderMenuPress={() => {
// Custom header menu action (opens thread drawer by default)
}}
onHeaderPlusPress={() => {
// Custom plus button action (creates new thread by default)
}}
/>;The library includes several native tools that work out of the box:
These tools are automatically available:
- todo_list: Interactive todo list management
- search_web: Web search functionality
The AI can use these tools automatically in function calls
// Create custom tool UI components
const CustomTimeTool = ({ request, submitQuery, onResponse }) => {
const { tool } = request;
const { timezone } = tool.args || {};
return (
<View>
<Text>Getting time for: {timezone}</Text>
{/* Your custom tool UI */}
</View>
);
};
<Ajora
tools={() => [
<CustomTimeTool key="get_current_time" toolName="get_current_time" />,
]}
/>;The ApiService class provides a comprehensive interface for communicating with AI agent servers via REST endpoints and Server-Sent Events (SSE) for real-time streaming.
import { ApiService } from "react-native-ajora";
const apiService = new ApiService({
baseUrl: "https://your-api-server.com",
bearerToken: "your-auth-token", // Optional
debug: true, // Optional, enables detailed logging
});The baseUrl you provide is intelligently processed:
-
Automatic
/apiappending: If your URL doesn't contain/apianywhere, it will be automatically appended"https://myserver.com"β"https://myserver.com/api""https://myserver.com/v1"β"https://myserver.com/v1/api"
-
Preserves existing API paths: If your URL already contains
/api, it remains unchanged"https://myserver.com/api"β"https://myserver.com/api""https://myserver.com/api/v3/agent"β"https://myserver.com/api/v3/agent"
-
Trailing slash normalization: Trailing slashes are automatically removed for consistency
const cleanup = apiService.streamResponse(
{
type: "text",
message: {
_id: "1",
role: "user",
parts: [{ text: "Hello, AI!" }],
createdAt: new Date(),
},
},
{
onChunk: (event) => {
console.log("New message chunk:", event.message);
},
onFunctionResponse: (event) => {
console.log("Tool response:", event.message);
},
onComplete: (event) => {
console.log("Stream completed");
},
onError: (error) => {
console.error("Stream error:", error);
},
}
);
// Clean up when done
cleanup();// Get all threads
const threads = await apiService.getThreads();
// Create a new thread
const newThread = await apiService.createThread("My New Conversation");
// Get messages from a thread
const { messages, pagination } = await apiService.getMessages(
"thread-id",
20,
0
);β Currently Supported:
- Text Messages: Full support for text-based conversations
- Image Messages: Upload and display images in conversations with lightbox viewing
- File Attachments: Support for document and file sharing (PDF, etc.)
- Tool/Function Calls: Complete integration with AI tools and function calling
- Server-Sent Events: Real-time streaming responses
- Thread Management: Multi-conversation support
- Authentication: Bearer token support
- File Upload Progress: Real-time upload progress tracking with error handling
<Ajora
messagesContainerStyle={{
backgroundColor: "#f0f0f0",
}}
renderBubble={(props) => <CustomBubble {...props} />}
renderInputToolbar={(props) => <CustomInputToolbar {...props} />}
renderMessage={(props) => <CustomMessage {...props} />}
renderMessageText={(props) => <CustomMessageText {...props} />}
renderHeader={(props) => <CustomHeader {...props} />}
renderThread={(props) => <CustomThread {...props} />}
renderMessageActions={(props) => <CustomMessageActions {...props} />}
/>For advanced use cases, you can use the useAjora hook directly:
import { useAjora } from "react-native-ajora";
const MyCustomChat = () => {
const ajora = useAjora({
baseUrl: "http://localhost:3000",
bearerToken: "your-token",
debug: true,
});
const {
messagesByThread,
threads,
activeThreadId,
isThinking,
submitQuery,
addNewThread,
switchThread,
stopStreaming,
regenerateMessage,
} = ajora;
return (
// Your custom chat UI
);
};The library expects a server that handles AI agent interactions:
// Server endpoints expected:
// GET /api/threads - Get user's conversation threads
// POST /api/threads - Create new thread
// GET /api/threads/:id/messages - Get messages for thread
// GET /api/stream - Stream AI response via Server-Sent Events (SSE)
// Example message format for API:
const userMessage = {
type: "text", // or "attachement", "function_response", "regenerate"
message: {
_id: "unique-id",
thread_id: "thread-id",
role: "user",
parts: [{ text: "Hello!" }],
createdAt: new Date().toISOString(),
},
mode: "assistant", // or "agent"
};
Beautiful chat interface with AI agent
Multi-thread conversation management
<Ajora
keyboardShouldPersistTaps="never" // "always" | "never" | "handled"
focusOnInputWhenOpeningKeyboard={true}
isKeyboardInternallyHandled={true}
bottomOffset={0} // Distance from screen bottom
/><Ajora
onSend={(messages) => console.log("Sent:", messages)}
onLoadEarlier={() => console.log("Loading earlier messages")}
onPress={(context, message) => console.log("Message pressed")}
onLongPress={(context, message) => console.log("Message long pressed")}
onInputTextChanged={(text) => console.log("Input changed:", text)}
onPressActionButton={() => console.log("Action button pressed")}
/>- Node.js >= 18
- React Native development environment
- Expo CLI (for example app)
- Clone the repository:
git clone https://github.com/habasefa/react-native-ajora.git
cd react-native-ajora- Install dependencies:
npm install- Start the example app:
npm startnpm run buildCheck out the included example applications:
- Complete Expo App - Full React Native app with Ajora integration
- Native Tools Demo - Showcases built-in AI tools (todo, search, confirm)
- Thread Management - Multi-conversation interface
- Custom Styling - Themed components and layouts
- Media Support - Image, audio, and file message examples with upload functionality
- Node.js Backend - Complete server implementation for AI agents
- Gemini AI Integration - Example using Google's Gemini AI
- Tool Execution - Server-side tool handling
- SSE Streaming - Real-time message streaming
- Database Integration - Message and thread persistence
- File Upload Handling - Complete file upload system with progress tracking
To run the examples:
# Install dependencies
npm install
# Start the example server
cd example-server
npm install && npm start
# In another terminal, start the example app
cd example-app
npm install && npm startWe welcome contributions! Please see our Contributing Guide for details.
- Fork the repository
- Create your feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'Add some amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
This project is licensed under the MIT License - see the LICENSE file for details.
// Main Components
import {
Ajora, // Main chat component
AjoraProvider, // Context provider
useAjora, // State management hook
} from "react-native-ajora";
// UI Components
import {
Actions, // Action button component
Bubble, // Message bubble component
Composer, // Text input component
InputToolbar, // Input toolbar container
LoadEarlier, // Load earlier button
Message, // Individual message component
MessageContainer, // Messages list container
MessageImage, // Image message component
MessageText, // Text message component
Send, // Send button component
} from "react-native-ajora";
// Types
import type {
IMessage, // Core message interface
Part, // Message part interface
FunctionCall, // Function call interface
FunctionResponse, // Function response interface
Thread, // Thread interface
AjoraProps, // Main component props
AjoraState, // Hook state type
} from "react-native-ajora";// Built-in tools available to AI agents:
const nativeTools = [
"todo_list", // Interactive todo list management
"search_web", // Web search functionality
"search_document", // Document search capabilities
];- Built with β€οΈ for the React Native community
- Inspired by modern chat interfaces and AI agent UIs
- Special thanks to Farid and react-native-giftedchat contributors
- Powered by React Native Reanimated, Expo Vector Icons, and other amazing open source libraries
- π§ Email: nazrihabtish@gmail.com
- π Issues: GitHub Issues
- π¬ Discussions: GitHub Discussions
Made with β€οΈ by Habtamu Asefa
β Star us on GitHub β’ π Documentation β’ π Report Bug β’ β¨ Request Feature

