showcase/shell-docs/src/content/reference/components/CopilotChatMessageView.mdx
CopilotChatMessageView renders a list of chat messages and, optionally, a typing cursor while the agent is running. It delegates rendering of individual messages to slot components (assistantMessage and userMessage) and supports a render-prop children function for full control over layout.
import { CopilotChatMessageView } from "@copilotkit/react-core/v2";
import "@copilotkit/react-core/v2/styles.css";
All slot props follow the CopilotKit slot system: each accepts a replacement React component, a className string that is merged into the default component's classes, or a partial props object that extends the default component.
As a replacement component:
<CopilotChatMessageView
assistantMessage={({ message }) => (
<div className="my-assistant-msg">{message.content}</div>
)}
/>
As a className:
<CopilotChatMessageView assistantMessage="bg-blue-50 rounded-lg" />
As partial props:
<CopilotChatMessageView assistantMessage={{ toolbarVisible: false }} />
As a replacement component:
<CopilotChatMessageView
userMessage={({ message }) => (
<div className="my-user-msg">{message.content}</div>
)}
/>
As a className:
<CopilotChatMessageView userMessage="bg-gray-100 rounded-lg" />
As a replacement component:
<CopilotChatMessageView
cursor={() => <span className="animate-bounce">...</span>}
/>
As a className:
<CopilotChatMessageView cursor="text-blue-500" />
function MessageList() {
const { agent } = useAgent();
return (
<CopilotChatMessageView
messages={agent.messages}
isRunning={agent.isRunning}
/>
);
}
function CustomMessages() {
const { agent } = useAgent();
return (
<CopilotChatMessageView
messages={agent.messages}
isRunning={agent.isRunning}
assistantMessage="bg-blue-50 p-4 rounded-xl"
userMessage="bg-gray-100 p-4 rounded-xl"
cursor={() => (
<div className="animate-pulse text-gray-400">Thinking...</div>
)}
/>
);
}
function CustomLayout() {
const { agent } = useAgent();
return (
<CopilotChatMessageView
messages={agent.messages}
isRunning={agent.isRunning}
>
{({ isRunning, messages, messageElements }) => (
<div className="flex flex-col gap-4 p-6">
<div className="text-sm text-gray-500">
{messages.length} message{messages.length !== 1 ? "s" : ""}
</div>
{messageElements}
{isRunning && (
<div className="text-sm text-blue-500 animate-pulse">
Agent is responding...
</div>
)}
</div>
)}
</CopilotChatMessageView>
);
}
function MinimalChat() {
const { agent } = useAgent();
return (
<CopilotChatMessageView
messages={agent.messages}
isRunning={agent.isRunning}
assistantMessage={{ toolbarVisible: false }}
/>
);
}
messages array is rendered using the corresponding slot component based on its role. Assistant messages use the assistantMessage slot; user messages use the userMessage slot.cursor slot is only rendered when isRunning is true. It appears after the last message in the list.children is provided as a function, the component delegates all layout to that function. The messageElements array is pre-built from the slot components, so custom layouts still benefit from slot customization.CopilotChatAssistantMessage -- Default assistant message slot componentCopilotChatUserMessage -- Default user message slot componentCopilotChatView -- Higher-level chat view that composes this component