Chat - Text and markdown
Render plain text and markdown content in chat messages with the built-in renderer.
Text parts are the most common message part. Every message with written content—whether from a human user or an AI assistant—uses one or more text parts to carry that content.
Text part structure
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.' },
],
};
The reasoning part shares the same structure (text plus optional state) and is rendered with the same markdown renderer — see Reasoning.
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, with no configuration needed.
The default renderer is streaming-aware: it repairs half-streamed markdown as tokens arrive, so partial syntax renders cleanly instead of leaking raw ** or unclosed code-fence markers mid-stream.
The built-in parser supports:
- Bold (
**text**or__text__) - Italic (
*text*or_text_) Inline code(`code`)- Links (
[label](url)) - Images (
) - Headings (
# H1through###### H6) - Ordered and unordered lists
- Code fences (rendered as
ChatCodeBlock) - Footnote citations (
[^1])
Markdown source
Rendered message
Customizing text rendering
Override the markdown renderer through partProps.text.renderText on ChatMessageContent:
<ChatBox
adapter={adapter}
slotProps={{
content: {
partProps: {
text: {
renderText: (text) => <MyCustomMarkdownRenderer content={text} />,
},
},
},
}}
/>
renderText receives the part's raw text string and returns any React node — the example below in Streaming text shows what you give up when replacing the built-in renderer.
This lets you plug in any markdown library (react-markdown, remark, MDX) while keeping the rest of the chat UI intact. Replacing renderText replaces the entire pipeline for that part — including streaming repair and code-fence routing. Code fences are rendered by the same built-in renderer, so a custom renderText also takes over code-block rendering — see Code blocks for rendering fences with your own component.
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', as shown below:
// During streaming
{ type: 'text', text: 'The answer is', state: 'streaming' }
// After completion
{ type: 'text', text: 'The answer is 42.', state: 'done' }
When composing a fully custom message renderer (for example with the headless package), use the part's state field 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 built-in Material UI renderer already handles this: it stays streaming-aware and repairs partial markdown automatically (see Markdown rendering). Note that partProps.text.renderText receives only the raw text string — if you need the part's state, you must take over part rendering entirely.
See also
- See Scrolling for how the message list follows streaming content.
- See Reasoning for the
reasoningpart, which shares the text part's structure and renderer. - See Code blocks for details on syntax-highlighted code fence rendering.
- See Message appearance for details on the 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.