Skip to content
+

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 (# H1 through ###### 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

API

See the documentation below for a complete reference to all of the props and classes available to the components mentioned here.