Skip to content
+

Chat - Messages

Render conversation history as a virtualized, grouped, auto-scrolling message list.

Interactive playground

Toggle role, status, density, and grouping on a single ChatMessage bubble:

ChatMessage (bubble)
Single message bubble—toggle role, status, density, grouping.

MUI Assistant
MUI Assistant

Default chat bubbles inherit palette.background.paper and divider automatically.

props
isGrouped
Render as a continuation of the previous bubble.
fixture (message data)
roleenum · 2
Stored on the message, read by useMessage().
statusenum · 4
content lengthenum · 4
chrome provider
ChatChrome.variantenum · 2
ChatChrome.densityenum · 3
variant and density mainly affect meta and bubble spacing—see the Meta and Inline meta playgrounds below.

Group playground

ChatMessageGroup collapses consecutive messages from the same author into a single visual cluster:

ChatMessageGroup
Wraps consecutive messages from the same author into a visual cluster.

MUI Assistant
MUI Assistant

Three quick notes on theming.

First—the avatar only renders for the first message in a group.

Second—bubbles tighten vertically when grouped.

Props
fixture data
message count3
authorenum · 2
interleave authors
Alternate authors so groups break.
chrome provider
ChatChrome.variantenum · 2
ChatChrome.densityenum · 3

List playground

ChatMessageList virtualizes rendering, manages auto-scroll, and can insert opt-in dividers between days:

ChatMessageList
Virtualised scroller with auto-scroll, opt-in date dividers and an overlay slot.

MUI Assistant
MUI Assistant

Message 8 from MUI Assistant.

Alice Chen

Message 7 from Alice Chen.

You

Message 6 from You.

MUI Assistant
MUI Assistant

Message 5 from MUI Assistant.

Alice Chen

Message 4 from Alice Chen.

You

Message 3 from You.

MUI Assistant
MUI Assistant

Message 2 from MUI Assistant.

Alice Chen

Message 1 from Alice Chen.

props
autoScroll
Stick to the bottom on new messages.
autoScroll buffer150px
Distance from bottom to still trigger auto-scroll.
features.dateDivider
Opt-in day separators between calendar days.
overlay
Demos the `overlay` slot for empty-state UI.
fixture data
message count8
span multiple days
Creates the day boundaries the divider renders at.
chrome provider
ChatChrome.variantenum · 2
ChatChrome.densityenum · 3

The ChatMessage data model

Every message in the chat system is represented by the ChatMessage interface:

import type { ChatMessage } from '@mui/x-chat/headless';

A ChatMessage has the following shape:

Field Type Description
id string Unique identifier for the message
role ChatRole 'user', 'assistant', or 'system'
parts ChatMessagePart[] Content parts that make up the message body (text, files, tools, etc.)
status ChatMessageStatus Delivery lifecycle: 'pending', 'sending', 'streaming', 'sent', 'read', 'error', or 'cancelled'
author ChatUser The author payload used for inline identity data and member matching
createdAt string ISO 8601 timestamp when the message was created
updatedAt string ISO 8601 timestamp when the message was last updated
editedAt string ISO 8601 timestamp if the message was edited
conversationId string The conversation this message belongs to
metadata ChatMessageMetadata Extensible metadata object for custom data

author.id is the canonical identity key for message rendering. If you pass members, currentUser, or active conversation participants, chat components use that id to enrich missing display names and avatars at render time.

If your message model stores author identity somewhere else, provide getMessageAuthorId, getMessageAuthorDisplayName, and getMessageAuthorAvatarUrl on ChatProvider, ChatRoot, or ChatBox to map that data into the built-in message primitives.

Message parts

The parts array is the core content model. Each part has a type discriminant that determines how it renders:

Part type Description
text Plain or markdown text content
reasoning Model reasoning / chain-of-thought text
file An attached file (image, document, etc.)
source-url A URL citation
source-document A document citation
tool A tool call invocation and its result
step-start A visual separator between agentic steps

This part-based model means a single message can contain mixed content—for example, a text explanation followed by a code block and a source citation.

Message status lifecycle

Messages progress through a status lifecycle:

pending → sending → streaming → sent → read
                 \→ error
                 \→ cancelled
  • pending—the message is queued but not yet dispatched to the adapter.
  • sending—the message has been dispatched; waiting for the first response chunk.
  • streaming—the assistant is actively generating tokens.
  • sent—the response is complete.
  • read—the recipient has seen the message. The runtime never infers this state; supply it from your data source or adapter. The meta slots render it as a double checkmark.
  • error—the adapter encountered an error.
  • cancelled—the user or application cancelled the response.

Import

import { ChatMessageList, ChatMessageGroup, ChatMessage } from '@mui/x-chat';

Component anatomy

Inside ChatBox, the message list renders a subtree of themed components:

ChatMessageList                     ← scrollable container
  MessageListDateDivider            ← date separator between message groups (opt-in)
  ChatMessageGroup                  ← groups consecutive same-author messages
    ChatMessage                     ← individual message row
      ChatMessageAvatar             ← author avatar
      ChatMessageContent            ← message bubble with part renderers
      ChatMessageMeta               ← timestamp, delivery status
      ChatMessageActions            ← hover action buttons

How messages render

The ChatMessageList component is the scrollable region that renders conversation history. It manages scroll behavior, overflow, padding, and a thin scrollbar by default.

Message groups

Consecutive messages from the same author are grouped together into a ChatMessageGroup. Within a group, only the first message displays the avatar, reducing visual repetition and making the conversation easier to scan. If no display name or avatar resolves for a message author, the UI omits those affordances instead of falling back to the role name.

See Message appearance for grouping configuration and demos.

Date dividers

When consecutive messages span different calendar dates, the message list can render a date divider between them. Dividers are disabled by default—enable them with the dateDivider feature flag:

<ChatBox adapter={adapter} features={{ dateDivider: true }} />

See Date divider and Message appearance for customization.

Auto-scrolling

The message list automatically scrolls to the bottom when the user sends a new message, when new assistant messages arrive, and during streaming.

See Scrolling for buffer configuration and scroll-to-bottom affordance.

Accessibility

The message list is a single Tab stop: a roving tabindex over the role="article" messages keeps only one message in the tab order at a time, so tabbing through the page never walks every message.

  • Arrow Up / Arrow Down and Home / End move between messages.
  • Enter drills into the focused message's links, copy buttons, and actions; Escape returns to the message.
  • The scroller is a role="log" polite live region, and a visually hidden role="status" region announces streaming transitions ("Assistant is responding" / "Response complete") exactly once each.
  • The thread, composer, and conversation list are exposed as labeled landmarks.

Tab into the list (a single stop), Arrow Up/Down between messages, Enter to drill into the focused message's links and buttons, Escape to come back, Tab onward to the composer.

Material UI chat

Styled with your active MUI theme

You
You

How do I move around this chat with the keyboard?

MUI Assistant
MUI Assistant

The message list is a single Tab stop — Arrow Up and Arrow Down move between messages.

You
You

And how do I reach a link or a copy button inside a message?

MUI Assistant
MUI Assistant

Press Enter on the focused message to drill into its controls, and Escape to come back. Try it here — this message has a link and a code block:

ts
import { ChatBox } from '@mui/x-chat';

Home and End jump to the first and latest message, and Page Up/Page Down scroll natively so long messages stay readable.

Set enableRovingFocus={false} on the message list to opt out, and use the useMessageContentTabIndex() hook from @mui/x-chat/headless to let custom interactive content participate.

See the complete model—including the drill-in lifecycle, per-list focus memory, and locale keys—on the Accessibility page and in Message list—Accessibility.

Standalone usage

When building a custom layout outside of ChatBox, render ChatMessageList inside ChatConversation within a ChatProvider. The demo below isolates the message surface with only the provider, an active conversation scope, a bounded frame, and the message list composition:

MUI Assistant
MUI Assistant

Hello! I am styled using your active Material UI theme. Try sending a message.

You
You

Great — the bubble colors come from palette.primary and the typography from the theme.

Message slots

Each slot inside the ChatMessage row has its own playground—iterate on a single surface at a time.

Avatar

The author avatar slot—falls back to initials when no avatarUrl is set.

ChatMessageAvatar
Author avatar slot—falls back to initials when no avatarUrl is set.

MUI Assistant
MUI Assistant

Avatar preview message.

fixture (message data)
roleenum · 2
chrome provider
ChatChrome.variantenum · 2

Author label

Displays the author name above grouped messages.

ChatMessageAuthorLabel
Author display name rendered above grouped messages.

MUI Assistant
fixture (message data)
roleenum · 2

Content

The bubble interior—renders markdown, code fences, and tool or source parts.

ChatMessageContent
Bubble interior—handles markdown, code fences and tool/source parts.

MUI Assistant
MUI Assistant

Markdown is rendered automatically:

  • bullet one
  • bullet two

Inline code works too.

fixture (message data)
roleenum · 2
contentenum · 2
chrome provider
ChatChrome.variantenum · 2

Meta

External timestamp and delivery status, used by compact bubbles.

ChatMessageMeta
External meta (timestamp + delivery status) used by compact bubbles.

Meta preview message.

fixture (message data)
roleenum · 2
statusenum · 3
chrome provider
ChatChrome.variantenum · 2

Inline meta

Telegram-style timestamp and status flowing inside the bubble.

ChatMessageInlineMeta
Telegram-style timestamp + status that flows inside the bubble.

You

Inline meta sits at the bottom-right of this bubble.

fixture (message data)
roleenum · 2
statusenum · 3

API

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