@xcelsior/ui-chat
v1.0.7
Published
A comprehensive, real-time chat widget component for React applications with WebSocket support, emoji picker, file uploads, and more.
Downloads
584
Readme
@xcelsior/ui-chat
A comprehensive, real-time chat widget component for React applications with WebSocket support, emoji picker, file uploads, and more.
Features
- 🔄 Real-time Communication: WebSocket-based instant messaging
- 💬 Rich Messages: Support for text, markdown, images, and files
- 🤖 AI Assistant: Visual differentiation for AI-generated messages with robot icon
- 😊 Emoji Support: Built-in emoji picker
- 📎 File Uploads: Upload and share files with progress tracking
- ⌨️ Typing Indicators: Show when users are typing
- ✓✓ Read Receipts: Track message delivery and read status
- 🎨 Customizable: Fully configurable appearance and behavior
- 📱 Responsive: Works great on all screen sizes
- 🌓 Dark Mode: Automatic dark mode support
- ♿ Accessible: Built with accessibility in mind
Installation
pnpm add @xcelsior/ui-chat @xcelsior/design-system @xcelsior/ui-fieldsPeer Dependencies
Make sure you have the following peer dependencies installed:
pnpm add react react-dom @tanstack/react-query react-hook-form flowbite-reactUsage
Basic Example
import { ChatWidget } from '@xcelsior/ui-chat';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
const queryClient = new QueryClient();
function App() {
const chatConfig = {
websocketUrl: 'wss://your-api.com/chat',
userId: 'user-123',
userType: 'customer',
conversationId: 'conv-456',
currentUser: {
id: 'user-123',
name: 'John Doe',
email: '[email protected]',
type: 'customer',
},
};
return (
<QueryClientProvider client={queryClient}>
<ChatWidget config={chatConfig} />
</QueryClientProvider>
);
}Chat Widget States (Bubble Mode)
The chat widget supports three states in popover mode:
open: Fully open with chat interface visibleminimized: Show bubble button only (default)closed: Fully hidden, no bubble visible
Uncontrolled Mode (Default)
By default, the widget starts in minimized state and manages its own state:
import { ChatWidget } from '@xcelsior/ui-chat';
function App() {
return (
<ChatWidget
config={chatConfig}
// Starts minimized by default
/>
);
}You can also set a different default state:
<ChatWidget
config={chatConfig}
defaultState="open" // or "minimized" or "closed"
/>Controlled Mode
Control the widget state externally:
import { ChatWidget, ChatWidgetState } from '@xcelsior/ui-chat';
import { useState } from 'react';
function App() {
const [chatState, setChatState] = useState<ChatWidgetState>('minimized');
return (
<>
<button onClick={() => setChatState('open')}>
Open Chat
</button>
<button onClick={() => setChatState('minimized')}>
Minimize Chat
</button>
<button onClick={() => setChatState('closed')}>
Close Chat
</button>
<ChatWidget
config={chatConfig}
state={chatState}
onStateChange={setChatState}
/>
</>
);
}Listen to State Changes (Semi-controlled)
You can listen to state changes while keeping the widget uncontrolled:
<ChatWidget
config={chatConfig}
defaultState="minimized"
onStateChange={(state) => {
console.log('Chat state changed to:', state);
// Save to localStorage, analytics, etc.
}}
/>With File Upload
The file upload feature uses a presigned URL approach for secure, direct-to-S3 uploads:
import { ChatWidget } from '@xcelsior/ui-chat';
const chatConfig = {
// ... other config
fileUpload: {
uploadUrl: 'https://your-api.com/attachments/upload-url',
maxFileSize: 10 * 1024 * 1024, // 10MB (default)
allowedTypes: [
'image/jpeg',
'image/png',
'image/gif',
'image/webp',
'application/pdf',
'application/msword',
'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
'text/plain',
'text/csv',
],
headers: {
'Authorization': 'Bearer your-token',
},
},
};
<ChatWidget config={chatConfig} />How it works:
- User selects a file
- Widget requests a presigned upload URL from your API (
POST /attachments/upload-url) - Widget uploads file directly to S3 using the presigned URL
- File becomes accessible via CloudFront CDN
- The CloudFront URL is inserted into the message as markdown
Backend API Contract:
// Request
POST /attachments/upload-url
{
"fileName": "document.pdf",
"contentType": "application/pdf",
"fileSize": 1234567
}
// Response
{
"data": {
"uploadUrl": "https://s3.amazonaws.com/...", // Presigned URL for upload
"attachmentUrl": "https://cdn.example.com/...", // Final public URL
"key": "attachments/uuid.pdf", // S3 key
"expiresIn": 300 // URL expiry (seconds)
}
}With Event Callbacks
import { ChatWidget } from '@xcelsior/ui-chat';
const chatConfig = {
// ... other config
onMessageSent: (message) => {
console.log('Message sent:', message);
},
onMessageReceived: (message) => {
console.log('Message received:', message);
},
onConnectionChange: (connected) => {
console.log('Connection status:', connected);
},
onError: (error) => {
console.error('Chat error:', error);
},
toast: {
success: (message) => console.log('Success:', message),
error: (message) => console.error('Error:', message),
info: (message) => console.log('Info:', message),
},
};
<ChatWidget config={chatConfig} />Configuration
IChatConfig
The main configuration object for the chat widget.
| Property | Type | Required | Description |
|----------|------|----------|-------------|
| websocketUrl | string | ✓ | WebSocket server URL |
| userId | string | ✓ | Current user's ID |
| userType | 'customer' \| 'agent' | ✓ | Type of user |
| currentUser | IUser | ✓ | Current user information |
| conversationId | string | | Conversation ID (auto-generated if not provided) |
| httpApiUrl | string | | REST API URL for fetching data |
| headers | Record<string, string> | | HTTP headers for API requests |
| fileUpload | IFileUploadConfig | | File upload configuration |
| enableEmoji | boolean | | Enable emoji picker (default: true) |
| enableFileUpload | boolean | | Enable file uploads (default: true) |
| enableTypingIndicator | boolean | | Enable typing indicators (default: true) |
| enableReadReceipts | boolean | | Enable read receipts (default: true) |
| onMessageSent | (message: IMessage) => void | | Callback when message is sent |
| onMessageReceived | (message: IMessage) => void | | Callback when message is received |
| onConnectionChange | (connected: boolean) => void | | Callback when connection status changes |
| onError | (error: Error) => void | | Callback when error occurs |
| toast | object | | Toast notification handlers |
IFileUploadConfig
Configuration for file uploads.
| Property | Type | Required | Description |
|----------|------|----------|-------------|
| uploadUrl | string | ✓ | Upload endpoint URL |
| maxFileSize | number | | Maximum file size in bytes (default: 5MB) |
| allowedTypes | string[] | | Allowed MIME types (default: images and PDFs) |
| headers | Record<string, string> | | Additional headers for upload request |
WebSocket Integration
The chat widget connects to your WebSocket API using the following protocol:
Connection
wss://your-api.com/chat?userId=user-123&userType=customer&conversationId=conv-456Sending Messages
{
"action": "sendMessage",
"data": {
"conversationId": "conv-456",
"content": "Hello!",
"messageType": "text"
}
}Receiving Messages
{
"type": "message",
"data": {
"id": "msg-789",
"conversationId": "conv-456",
"senderId": "agent-123",
"senderType": "agent",
"content": "Hi! How can I help?",
"messageType": "text",
"createdAt": "2025-10-28T12:00:00Z",
"status": "delivered"
}
}Typing Indicator
{
"action": "typing",
"data": {
"conversationId": "conv-456",
"isTyping": true
}
}REST API Integration
The chat widget can fetch existing messages from your REST API when httpApiUrl is provided in the config.
Fetching Messages
When the widget loads or the conversationId changes, it will automatically fetch existing messages:
GET /messages?conversationId=conv-456&limit=50Expected response format:
{
"success": true,
"data": {
"items": [...messages],
"nextPageToken": "optional-pagination-token"
}
}or alternatively:
{
"success": true,
"data": [...messages],
"nextToken": "optional-pagination-token"
}Example with HTTP API
const chatConfig = {
websocketUrl: 'wss://your-api.com/chat',
httpApiUrl: 'https://your-api.com',
conversationId: 'conv-456',
headers: {
'Authorization': 'Bearer your-token',
},
// ... other config
};
<ChatWidget config={chatConfig} />Performance Optimizations
Debounced Typing Indicator
The typing indicator is now debounced to reduce unnecessary WebSocket messages:
- Start typing: Sent after 300ms of typing activity
- Stop typing: Sent after 1.5s of inactivity
- This reduces WebSocket traffic while maintaining responsive user feedback
Components
ChatWidget
The main chat widget component that includes all features.
import { ChatWidget } from '@xcelsior/ui-chat';
<ChatWidget config={chatConfig} className="custom-class" />Individual Components
For custom implementations, you can use individual components:
MessageList
import { MessageList } from '@xcelsior/ui-chat';
<MessageList
messages={messages}
currentUser={currentUser}
isTyping={false}
autoScroll={true}
/>MessageItem
Displays individual messages with automatic icon detection:
- 🤖 Robot icon for AI-generated messages (when
metadata.isAI === true) - 🎧 Headset icon for human agent messages
- 👤 User icon for customer messages
import { MessageItem } from '@xcelsior/ui-chat';
// Regular agent message
<MessageItem
message={message}
currentUser={currentUser}
showAvatar={true}
showTimestamp={true}
/>
// AI-generated message (automatically shows robot icon)
<MessageItem
message={{
...message,
senderType: 'agent',
metadata: { isAI: true }
}}
currentUser={currentUser}
showAvatar={true}
showTimestamp={true}
/>ChatInput
import { ChatInput } from '@xcelsior/ui-chat';
<ChatInput
onSend={handleSend}
onTyping={handleTyping}
config={chatConfig}
fileUpload={fileUploadHook}
/>ChatHeader
import { ChatHeader } from '@xcelsior/ui-chat';
<ChatHeader
agent={agent}
onClose={handleClose}
onMinimize={handleMinimize}
/>Hooks
useWebSocket
Custom hook for WebSocket connection management.
import { useWebSocket } from '@xcelsior/ui-chat';
const { isConnected, sendMessage, lastMessage, error, reconnect } = useWebSocket(config);useMessages
Custom hook for message management.
import { useMessages } from '@xcelsior/ui-chat';
const { messages, addMessage, updateMessageStatus, clearMessages } = useMessages(websocket, config);useFileUpload
Custom hook for file uploads.
import { useFileUpload } from '@xcelsior/ui-chat';
const { uploadFile, isUploading, uploadProgress, error, canUpload } = useFileUpload(config);useTypingIndicator
Custom hook for typing indicators.
import { useTypingIndicator } from '@xcelsior/ui-chat';
const { isTyping, typingUsers } = useTypingIndicator(websocket);Styling
The component uses Tailwind CSS for styling and supports dark mode automatically. You can customize the appearance by:
- Using the className prop: Pass custom classes to the ChatWidget component
- Overriding CSS variables: Define custom CSS variables for colors and sizes
- Using Tailwind configuration: Extend your Tailwind config to customize the design system
Backend Integration
This package is designed to work with the @xcelsior/chat-api backend service. For more information on setting up the backend, see the chat-api documentation.
Required Backend Endpoints
WebSocket: For real-time communication
$connect: Handle new connections$disconnect: Handle disconnectionssendMessage: Handle message sendingtyping: Handle typing indicators
REST API (optional): For fetching historical data
GET /messages?conversationId=xxx: Fetch message historyGET /conversations/:id: Fetch conversation details
File Upload API (optional): For file attachment support
POST /attachments/upload-url: Generate presigned S3 upload URL- Request:
{ fileName, contentType, fileSize } - Response:
{ uploadUrl, attachmentUrl, key, expiresIn }
- Request:
Examples
Check out the Storybook for live examples and interactive demos:
pnpm storybookDevelopment
Build
pnpm buildDevelopment Mode
pnpm devStorybook
pnpm storybookLint
pnpm lintTypeScript
This package is written in TypeScript and includes full type definitions. All types are exported from the main package:
import type {
IChatConfig,
IMessage,
IUser,
IConversation,
MessageType,
MessageStatus,
} from '@xcelsior/ui-chat';Browser Support
- Chrome (latest)
- Firefox (latest)
- Safari (latest)
- Edge (latest)
WebSocket support is required.
License
MIT
Support
For issues and questions, please contact the development team or create an issue in the repository.
