Chat - Text & Markdown
Render plain text and markdown content in chat messages using the ChatTextMessagePart type and the built-in markdown renderer.
Text parts are the most common message part type. Every message with written content — whether from a human user or an AI assistant — uses one or more text parts to carry that content.
The text part data model
A text part is represented by the ChatTextMessagePart interface:
interface ChatTextMessagePart {
type: 'text';
text: string;
state?: 'streaming' | 'done';
}
A message can contain multiple text parts alongside other part types (files, sources, tool calls). The parts array on ChatMessage holds them all:
const message: ChatMessage = {
id: 'msg-1',
role: 'assistant',
parts: [
{ type: 'text', text: 'Here is the analysis you requested:' },
{
type: 'file',
mediaType: 'image/png',
url: '/chart.png',
filename: 'chart.png',
},
{ type: 'text', text: 'The chart shows a 15% increase in Q4.' },
],
};
Markdown rendering
When using ChatBox with the Material UI layer (@mui/x-chat), text parts are rendered through a built-in markdown parser that converts common markdown syntax into React elements. This happens automatically — no configuration is needed.
The built-in parser supports:
- Bold (
**text**or__text__) - Italic (
*text*or_text_) Inline code(`code`)- Links (
[label](url)) - Headings (
# H1through###### H6) - Ordered and unordered lists
- Code fences (rendered as
ChatCodeBlock) - Footnote citations (
[^1])
Customizing text rendering
Override the markdown renderer through partProps.text.renderText on ChatMessageContent:
<ChatBox
adapter={adapter}
slotProps={{
messageContent: {
partProps: {
text: {
renderText: (text) => <MyCustomMarkdownRenderer content={text} />,
},
},
},
}}
/>
This lets you plug in any markdown library (react-markdown, remark, MDX) while keeping the rest of the chat UI intact.
Streaming text
Text parts support incremental delivery through the streaming protocol. The stream uses three chunk types to build up a text part:
| Chunk type | Purpose |
|---|---|
text-start |
Opens a new text part |
text-delta |
Appends a string fragment |
text-end |
Marks the text part as complete |
While tokens are arriving, the part's state field is 'streaming'. Once the text-end chunk arrives, state transitions to 'done'.
// During streaming
{ type: 'text', text: 'The answer is', state: 'streaming' }
// After completion
{ type: 'text', text: 'The answer is 42.', state: 'done' }
Use state to show a typing indicator or pulsing cursor while content is arriving:
function TextPartDisplay({ part }: { part: ChatTextMessagePart }) {
return (
<span>
{part.text}
{part.state === 'streaming' && <span className="cursor" />}
</span>
);
}
The message list auto-scrolls to follow new streaming content as long as the user is near the bottom of the list.
See also
- Code Blocks for syntax-highlighted code fence rendering
- Message Appearance for visual presentation of the message list
API
See the documentation below for a complete reference to all of the props and classes available to the components mentioned here.