Chat Conversation Block
The Chat Conversation Component is a fully customizable and accessible chat interface built with React and TypeScript. It provides a complete conversation view with message display, input handling, and flexible customization options for real-time messaging applications.
π Installationβ
npm install @nodeblocks/frontend-chat-conversation-block
π Usageβ
import {ChatConversation} from '@nodeblocks/frontend-chat-conversation-block';
- Basic Usage
- Advanced Usage
Live Editor
function BasicChatConversation() { const [messages, setMessages] = useState([ { title: 'John Doe', content: 'Hello! How are you doing today?', id: 'message-001', createdAt: '2025-02-01T10:00:00Z', isOwnMessage: false, }, { title: 'You', content: 'Hi! I am doing great, thanks for asking!', id: 'message-002', createdAt: '2025-02-01T10:01:00Z', isOwnMessage: true, }, ]); return ( <ChatConversation chatView={{ heading: { avatar: { avatarColor: '4', avatarSize: 'large', }, buttonHref: '/home', }, isLoading: false, }} onInputChange={(text) => { console.log('Input changed:', text); }} onMessageSubmit={(text) => { console.log('Message submitted:', text); setMessages(prev => [...prev, { title: 'You', content: text, id: 'message-' + Date.now(), createdAt: new Date().toISOString(), isOwnMessage: true, }]); }} commentInput={{ isDisabled: false, }} commentSubmitButton={{ isDisabled: false, }} messages={messages} labels={{ chatViewHeadingButtonText: 'Home', chatViewHeadingText: 'Conversation', }} onNavigate={(url) => { console.log('Navigate to:', url); }} placeholders={{ commentInput: 'Type a message...', }}> <ChatConversation.Heading /> <ChatConversation.Body /> </ChatConversation> ); }
Result
Loading...
Live Editor
function AdvancedChatConversation() { const [messages, setMessages] = useState([ { title: 'Support Team', content: 'Welcome to our support chat! How can we help you today?', id: 'message-001', createdAt: '2025-02-01T10:00:00Z', isOwnMessage: false, avatarColor: '1', avatarUrl: '/support-avatar.jpg', }, { title: 'You', content: 'I need help with my account settings.', id: 'message-002', createdAt: '2025-02-01T10:01:00Z', isOwnMessage: true, }, ]); return ( <ChatConversation chatView={{ isLoading: false, }} onInputChange={(text) => { console.log('Input changed:', text); }} onMessageSubmit={(text) => { console.log('Message submitted:', text); setMessages(prev => [...prev, { title: 'You', content: text, id: 'message-' + Date.now(), createdAt: new Date().toISOString(), isOwnMessage: true, }]); }} commentInput={{ isDisabled: false, errorText: '', }} commentSubmitButton={{ isDisabled: false, }} messages={messages} labels={{ chatViewHeadingButtonText: 'Dashboard', chatViewHeadingText: 'Support Chat', }} onNavigate={(url) => { console.log('Navigate to:', url); }} placeholders={{ commentInput: 'Ask a question...', }}> {({ defaultBlocks, defaultBlockOrder }) => ({ blocks: { ...defaultBlocks, // π¨ Custom heading with enhanced styling heading: { ...defaultBlocks.heading, props: { ...defaultBlocks.heading.props, className: 'custom-chat-heading', style: { backgroundColor: '#f0f8ff', borderBottom: '2px solid #007bff', padding: '20px', }, }, }, // π¬ Custom body with enhanced chat view body: { ...defaultBlocks.body, props: { ...defaultBlocks.body.props, className: 'custom-chat-body', size: 'large', style: { backgroundColor: '#fafafa', border: '1px solid #e0e0e0', borderRadius: '8px', }, }, }, // π§ Custom toolbar above chat toolbar: ( <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', padding: '12px 16px', backgroundColor: '#e7f3ff', borderBottom: '1px solid #b3d9ff', fontSize: '14px', color: '#0066cc', }}> <span>π’ Online - Support Agent</span> <span>Response time: ~2 min</span> </div> ), // π Custom status bar below statusBar: ( <div style={{ display: 'flex', justifyContent: 'center', alignItems: 'center', padding: '8px', backgroundColor: '#f8f9fa', borderTop: '1px solid #dee2e6', fontSize: '12px', color: '#6c757d', }}> <span>π¬ {messages.length} messages β’ Last updated: {new Date().toLocaleTimeString()}</span> </div> ), }, blockOrder: ['heading', 'toolbar', 'body', 'statusBar'], })} </ChatConversation> ); }
Result
Loading...
π§ Props Referenceβ
Main Component Propsβ
Prop | Type | Default | Description |
---|---|---|---|
onMessageSubmit | (text: string) => void | undefined | Callback when submitting a message |
onInputChange | (text: string) => void | undefined | Callback on comment input change |
commentInput | {isDisabled?: boolean; errorText?: string;} | undefined | Configuration for the comment input at the bottom |
commentSubmitButton | {isDisabled?: boolean;} | undefined | Configuration for the comment submit button |
chatView | ChatViewConfig | Required | Chat panel configuration |
messages | Message[] | Required | Array of messages to display in the chat view |
labels | LabelsConfig | Required | Label text configuration |
onNavigate | (url: string) => void | Required | Navigation callback (required for href) |
placeholders | {commentInput: string} | Required | Placeholder text configuration |
className | string | undefined | Additional CSS class name for styling |
children | BlocksOverride | undefined | Custom block components to override default rendering |
Sub-Componentsβ
The ChatConversation component provides several sub-components. All sub-components receive their default values from the main component's context and can override these values through props.
ChatConversation.Headingβ
Prop | Type | Default | Description |
---|---|---|---|
labels | LabelsConfig | Context values | Label configuration (overrides context) |
chatView | ChatViewConfig | Context values | Chat view configuration (overrides context) |
onNavigate | (url: string) => void | Context values | Navigation callback (overrides context) |
className | string | undefined | Additional CSS class name for styling |
children | ReactNode | Default heading content | Custom content to override default heading |
Note: This component inherits all HTML div
element props.
ChatConversation.Bodyβ
Prop | Type | Default | Description |
---|---|---|---|
onMessageSubmit | (text: string) => void | Context values | Message submit callback (overrides context) |
onInputChange | (text: string) => void | Context values | Input change callback (overrides context) |
commentInput | {isDisabled?: boolean; errorText?: string;} | Context values | Comment input configuration (overrides context) |
commentSubmitButton | {isDisabled?: boolean;} | Context values | Submit button configuration (overrides context) |
chatView | ChatViewConfig | Context values | Chat view configuration (overrides context) |
messages | Message[] | Context values | Messages array (overrides context) |
onNavigate | (url: string) => void | Context values | Navigation callback (overrides context) |
placeholders | {commentInput: string} | Context values | Placeholder configuration (overrides context) |
className | string | undefined | Additional CSS class name for styling |
size | "normal" | "large" | "normal" | Size variant for the chat view |
π§ TypeScript Supportβ
Full TypeScript support with comprehensive type definitions:
import {ChatConversation} from '@nodeblocks/frontend-chat-conversation-block';
import {AvatarProps} from '@basaldev/blocks-frontend-framework';
import {useState} from 'react';
interface LabelsConfig {
chatViewHeadingButtonText?: string;
chatViewHeadingText?: string;
}
interface ChatViewConfig {
heading?: {
avatar?: AvatarProps;
buttonHref: string;
};
isLoading?: boolean;
onScrollTop?: (earliestMessageId: string) => void;
}
// Message interface
interface Message {
avatarColor?: AvatarProps['avatarColor'];
avatarHref?: AvatarProps['href'];
avatarUrl?: AvatarProps['avatarUrl'];
content: string;
createdAt: string;
id: string;
isOwnMessage?: boolean;
title?: string;
}
// Complete chat conversation configuration
function AdvancedChatConversation() {
const [messages, setMessages] = useState<Message[]>([
{
title: 'Support Agent',
content: 'Hello! How can I help you today?',
id: 'msg-001',
createdAt: '2025-02-01T09:00:00Z',
isOwnMessage: false,
avatarColor: '1',
},
{
title: 'You',
content: 'I need help with my account settings.',
id: 'msg-002',
createdAt: '2025-02-01T09:01:00Z',
isOwnMessage: true,
},
]);
const [inputValue, setInputValue] = useState('');
const [isSubmitting, setIsSubmitting] = useState(false);
const [inputError, setInputError] = useState<string | undefined>();
const handleInputChange = (text: string) => {
setInputValue(text);
// Custom validation
if (text.length > 500) {
setInputError('Message too long (max 500 characters)');
} else {
setInputError(undefined);
}
};
const handleMessageSubmit = async (text: string) => {
if (!text.trim()) return;
setIsSubmitting(true);
// Add user message
const userMessage: Message = {
title: 'You',
content: text,
id: `msg-${Date.now()}`,
createdAt: new Date().toISOString(),
isOwnMessage: true,
};
setMessages(prev => [...prev, userMessage]);
setInputValue('');
// Simulate API call
try {
await new Promise(resolve => setTimeout(resolve, 2000));
// Add response message
const responseMessage: Message = {
title: 'Support Agent',
content: 'Thank you for your message. Let me help you with that.',
id: `msg-${Date.now()}-response`,
createdAt: new Date().toISOString(),
isOwnMessage: false,
avatarColor: '1',
};
setMessages(prev => [...prev, responseMessage]);
} catch (error) {
console.error('Failed to send message:', error);
} finally {
setIsSubmitting(false);
}
};
const handleScrollTop = (earliestMessageId: string) => {
console.log('Loading more messages before:', earliestMessageId);
// Implement pagination logic here
};
return (
<ChatConversation
chatView={{
heading: {
avatar: {
avatarColor: '2',
avatarSize: 'large',
avatarUrl: '/path/to/avatar.jpg',
},
buttonHref: '/support/dashboard',
},
isLoading: isSubmitting,
onScrollTop: handleScrollTop,
}}
onInputChange={handleInputChange}
onMessageSubmit={handleMessageSubmit}
commentInput={{
isDisabled: isSubmitting,
errorText: inputError,
}}
commentSubmitButton={{
isDisabled: isSubmitting || Boolean(inputError) || !inputValue.trim(),
}}
messages={messages}
labels={{
chatViewHeadingButtonText: 'Back to Dashboard',
chatViewHeadingText: 'Customer Support',
}}
onNavigate={(url) => {
// Handle navigation
window.location.href = url;
}}
placeholders={{
commentInput: 'Type your message here...',
}}
className="custom-chat-container"
style={{ maxHeight: '600px' }}>
<ChatConversation.Heading className="custom-chat-header" />
<ChatConversation.Body
className="custom-chat-body"
size="large"
/>
</ChatConversation>
);
}
Built with β€οΈ using React, TypeScript, and modern web standards.