Message Content
Component for displaying the content of conversation messages
The MessageContent component renders the actual content of a conversation message, including text parts, thinking indicators, and timestamps. It handles multiple text parts and automatically shows a thinking indicator for empty messages.
import { MessageContent } from "@pipecat-ai/voice-ui-kit";
<MessageContent
message={{
role: "assistant",
parts: [{ text: "Hello! This is a message." }],
createdAt: new Date().toISOString()
}}
/>Component Variants
MessageContent
The MessageContent component displays message content with thinking indicator and timestamp.
import { MessageContent } from "@pipecat-ai/voice-ui-kit";
<MessageContent
message={{
role: "assistant",
parts: [{ text: "Message content here" }],
createdAt: new Date().toISOString()
}}
/>| Prop | Type | Default |
|---|---|---|
message | ConversationMessage | - |
botOutputRenderers? | Record<string, (content: string, metadata: { spoken: string; unspoken: string }) => React.ReactNode> | undefined |
aggregationMetadata? | Record<string, { displayMode?: 'inline' | 'block'; isSpoken?: boolean }> | undefined |
classNames? | { messageContent?: string; thinking?: string; time?: string; } | {} |
Usage
Basic Usage
Display message content with default styling.
import { MessageContent } from "@pipecat-ai/voice-ui-kit";
<MessageContent
message={{
role: "assistant",
parts: [{ text: "Hello! How can I help you?" }],
createdAt: new Date().toISOString()
}}
/>Multiple Parts
Messages can contain multiple text parts that are rendered with proper spacing.
import { MessageContent } from "@pipecat-ai/voice-ui-kit";
<MessageContent
message={{
role: "assistant",
parts: [
{ text: "First part. " },
{ text: "Second part. " },
{ text: "Third part." }
],
createdAt: new Date().toISOString()
}}
/>Empty Message (Thinking)
Empty messages automatically show a thinking indicator.
import { MessageContent } from "@pipecat-ai/voice-ui-kit";
<MessageContent
message={{
role: "assistant",
parts: [],
createdAt: new Date().toISOString()
}}
/>Custom Styling
Apply custom classes to different parts of the content.
import { MessageContent } from "@pipecat-ai/voice-ui-kit";
<MessageContent
message={{
role: "assistant",
parts: [{ text: "Custom styled content" }],
createdAt: new Date().toISOString()
}}
classNames={{
messageContent: "text-lg leading-relaxed",
thinking: "text-muted-foreground",
time: "text-xs opacity-75"
}}
/>BotOutput with Custom Renderers
Use custom renderers for BotOutput content based on aggregation type. The component automatically detects BotOutputText objects and uses the appropriate renderer based on the aggregatedBy field.
import { MessageContent } from "@pipecat-ai/voice-ui-kit";
<MessageContent
message={{
role: "assistant",
parts: [{
text: { spoken: "Here's some code:", unspoken: "print('Hello')" },
final: false,
createdAt: new Date().toISOString(),
aggregatedBy: "code"
}],
createdAt: new Date().toISOString()
}}
aggregationMetadata={{
// Custom types are arbitrary: configure them in your app
code: { displayMode: "block", isSpoken: false },
}}
botOutputRenderers={{
code: (content, { spoken, unspoken }) => (
<div>
<span>{spoken}</span>
<pre className="bg-gray-100 p-2 rounded mt-1">{unspoken}</pre>
</div>
),
link: (content, { spoken, unspoken }) => (
<a href={unspoken} className="text-blue-500 underline">
{spoken || unspoken}
</a>
)
}}
/>When a custom renderer is provided for the aggregatedBy type, it receives:
content: The full content string (spoken + unspoken)metadata.spoken: The spoken portion of the textmetadata.unspoken: The unspoken portion of the text
If no custom renderer is provided, the component defaults to showing spoken text normally and unspoken text in a muted color.
Behavior
The component:
- Renders all text parts from
message.partsarray - Groups parts by display mode: inline parts render together, block parts render on their own line
- Shows a
Thinkingcomponent if the message has no parts or all parts are empty whitespace - Displays a formatted timestamp using
toLocaleTimeString()
Message Parts
Each message part can have a text property containing either:
- A string or ReactNode for regular text content
- A
BotOutputTextobject withspokenandunspokenproperties for assistant messages with BotOutput mode
The component:
- Renders text parts sequentially
- Adds spaces between consecutive text parts
- Handles BotOutput text by showing spoken text normally and unspoken text in muted color
- Supports custom renderers for BotOutput content based on
aggregatedBytype - Handles empty or whitespace-only parts by showing thinking indicator
Integration
The MessageContent component is typically used within MessageContainer to render the content portion of a message. It uses the Thinking component to show loading/thinking states.