Message Status
The MessageStatus component displays loading, complete, and error states with
optional multi-step progress indicators β useful for tool-call status, agent
step traces, and any long-running operation embedded in a chat response.
Overview
The MessageStatus component provides:
- Visual status indicators (loading, complete, error)
- Animated state transitions
- Multi-step progress display
- Customizable icons
- Support for nested status steps
Basic Usage
Display a simple status message:
import { MessageStatus } from 'reachat';
<MessageStatus
status="loading"
text="Processing your request..."
/>Status States
The component supports three status states:
Loading State
<MessageStatus
status="loading"
text="Analyzing data..."
/>Complete State
<MessageStatus
status="complete"
text="Analysis complete"
/>Error State
<MessageStatus
status="error"
text="Failed to process request"
/>Multi-Step Status
Display progress across multiple steps:
<MessageStatus
status="loading"
text="Processing request"
steps={[
{ id: '1', text: 'Validating input', status: 'complete' },
{ id: '2', text: 'Fetching data', status: 'complete' },
{ id: '3', text: 'Analyzing results', status: 'loading' },
{ id: '4', text: 'Generating report', status: 'loading' }
]}
/>Live Preview
Below is <MessageStatus> rendered on its own with multi-step progress:
Using in Conversations
<MessageStatus> can be rendered inline inside the messages list β for example,
above the next conversation while a tool call is running:
<SessionMessages>
{(conversations) => (
<>
{conversations.map((conversation) => (
<SessionMessage
key={conversation.id}
conversation={conversation}
/>
))}
{isToolRunning && (
<MessageStatus
status="loading"
text="Running tool"
steps={steps}
/>
)}
</>
)}
</SessionMessages>Advanced Examples
Dynamic Status Updates
Update status as operations progress:
import { useState, useEffect } from 'react';
import { MessageStatus } from 'reachat';
function AnalysisStatus() {
const [steps, setSteps] = useState([
{ id: '1', text: 'Initializing', status: 'loading' },
{ id: '2', text: 'Processing data', status: 'loading' },
{ id: '3', text: 'Generating insights', status: 'loading' }
]);
useEffect(() => {
// Simulate progress
const timers = [
setTimeout(() => updateStep('1', 'complete'), 1000),
setTimeout(() => updateStep('2', 'complete'), 2000),
setTimeout(() => updateStep('3', 'complete'), 3000)
];
return () => timers.forEach(clearTimeout);
}, []);
const updateStep = (id: string, status: string) => {
setSteps(prev => prev.map(step =>
step.id === id ? { ...step, status } : step
));
};
const allComplete = steps.every(s => s.status === 'complete');
return (
<MessageStatus
status={allComplete ? 'complete' : 'loading'}
text={allComplete ? 'Analysis complete' : 'Running analysis'}
steps={steps}
/>
);
}Error Handling
Display errors with specific step failures:
<MessageStatus
status="error"
text="Analysis failed"
steps={[
{ id: '1', text: 'Load dataset', status: 'complete' },
{ id: '2', text: 'Validate schema', status: 'complete' },
{ id: '3', text: 'Run computation', status: 'error' }
]}
/>Custom Icons
Provide custom icons for status states:
import { CheckCircle, XCircle, Loader } from 'lucide-react';
<MessageStatus
status="loading"
text="Custom status indicator"
icon={<Loader className="animate-spin" />}
/>Nested in Markdown
Include status indicators in markdown responses:
const conversationWithStatus = {
id: '1',
question: 'Run the analysis',
response: `I'm running the analysis now.
<MessageStatus
status="loading"
text="Analyzing data"
steps={[
{ id: '1', text: 'Loading dataset', status: 'complete' },
{ id: '2', text: 'Computing statistics', status: 'loading' }
]}
/>
I'll let you know when it's complete.`,
createdAt: new Date('2024-01-15T10:00:00Z')
};Integration with Custom Components
Use with custom markdown components:
import { Chat, MessageStatus } from 'reachat';
<Chat
markdownComponents={{
MessageStatus: (props) => (
<MessageStatus
{...props}
className="my-custom-status"
/>
)
}}
>
{/* ... */}
</Chat>Real-World Example
Complete example wiring <MessageStatus> to a fetch call. The state machine
keeps a single status object that we mutate on every transition:
import { useState } from 'react';
import { Chat, MessageStatus, ChatInput } from 'reachat';
type Status = {
status: 'loading' | 'complete' | 'error';
text: string;
steps: { id: string; text: string; status: 'loading' | 'complete' | 'error' }[];
};
function ChatWithStatus() {
const [status, setStatus] = useState<Status | null>(null);
const handleSendMessage = async (message: string) => {
setStatus({
status: 'loading',
text: 'Processing request',
steps: [
{ id: '1', text: 'Sending request', status: 'loading' },
{ id: '2', text: 'Waiting for response', status: 'loading' }
]
});
try {
// Mark step 1 complete once the request is in-flight.
setStatus(prev =>
prev && {
...prev,
steps: prev.steps.map((s, i) =>
i === 0 ? { ...s, status: 'complete' } : s
)
}
);
const response = await fetch('/api/chat', {
method: 'POST',
body: JSON.stringify({ message })
});
await response.json();
// Mark all steps complete on success.
setStatus(prev =>
prev && {
status: 'complete',
text: 'Response received',
steps: prev.steps.map(s => ({ ...s, status: 'complete' }))
}
);
} catch (error) {
setStatus(prev =>
prev && {
status: 'error',
text: 'Request failed',
steps: prev.steps.map(s => ({ ...s, status: 'error' }))
}
);
}
};
return (
<Chat sessions={sessions} onSendMessage={handleSendMessage}>
<SessionMessagePanel>
<SessionMessages />
{status && <MessageStatus {...status} />}
<ChatInput />
</SessionMessagePanel>
</Chat>
);
}API Reference
MessageStatusProps
MessageStatusStep
| Name | Type | Default |
|---|---|---|
id | stringUnique identifier for the step. | |
text | stringText to display for the step. | |
status | MessageStatusStateCurrent state of the step. | 'loading' |
For more examples and interactive demos, visit the storybook demosΒ .