Skip to main content

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@0.1.1

📖 Usage

import {ChatConversation} from '@nodeblocks/frontend-chat-conversation-block';
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>
);
}

🔧 Props Reference

Main Component Props

PropTypeDefaultDescription
onMessageSubmit(text: string) => voidundefinedCallback when submitting a message
onInputChange(text: string) => voidundefinedCallback on comment input change
commentInput{isDisabled?: boolean; errorText?: string;}undefinedConfiguration for the comment input at the bottom
commentSubmitButton{isDisabled?: boolean;}undefinedConfiguration for the comment submit button
chatViewChatViewConfigRequiredChat panel configuration
messagesMessage[]RequiredArray of messages to display in the chat view
labelsLabelsConfigRequiredLabel text configuration
onNavigate(url: string) => voidRequiredNavigation callback (required for href)
placeholders{commentInput: string}RequiredPlaceholder text configuration
classNamestringundefinedAdditional CSS class name for styling
childrenBlocksOverrideundefinedCustom 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

PropTypeDefaultDescription
labelsLabelsConfigContext valuesLabel configuration (overrides context)
chatViewChatViewConfigContext valuesChat view configuration (overrides context)
onNavigate(url: string) => voidContext valuesNavigation callback (overrides context)
classNamestringundefinedAdditional CSS class name for styling
childrenReactNodeDefault heading contentCustom content to override default heading

Note: This component inherits all HTML div element props.

ChatConversation.Body

PropTypeDefaultDescription
onMessageSubmit(text: string) => voidContext valuesMessage submit callback (overrides context)
onInputChange(text: string) => voidContext valuesInput change callback (overrides context)
commentInput{isDisabled?: boolean; errorText?: string;}Context valuesComment input configuration (overrides context)
commentSubmitButton{isDisabled?: boolean;}Context valuesSubmit button configuration (overrides context)
chatViewChatViewConfigContext valuesChat view configuration (overrides context)
messagesMessage[]Context valuesMessages array (overrides context)
onNavigate(url: string) => voidContext valuesNavigation callback (overrides context)
placeholders{commentInput: string}Context valuesPlaceholder configuration (overrides context)
classNamestringundefinedAdditional 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.