Components for rendering message content, parts, and attachments.
A single message in a conversation. Messages may consist of multiple parts.
Anatomy
import { MessagePrimitive } from "@assistant-ui/react";
const UserMessage = () => (
<MessagePrimitive.Root>
User: <MessagePrimitive.Parts />
<BranchPicker />
<ActionBar />
</MessagePrimitive.Root>
);
const AssistantMessage = () => (
<MessagePrimitive.Root>
Assistant: <MessagePrimitive.Parts />
<BranchPicker />
<ActionBar />
</MessagePrimitive.Root>
);API Reference
Root
Contains all parts of the message.
This primitive renders a <div> element unless asChild is set.
MessagePrimitiveRootPropsasChild: boolean= falseChange the default rendered element for the one passed as a child, merging their props and behavior.
Read the Composition guide for more details.
Parts
The content of the message. This renders a separate component for each message part.
MessagePrimitivePartsPropscomponents?: MessagePartComponentsThe components to render for each message part.
MessagePartComponentsText?: TextMessagePartComponentThe component to render for each text message part.
Image?: ImageMessagePartComponentThe component to render for each image message part.
Source?: SourceMessagePartComponentThe component to render for each source message part.
File?: FileMessagePartComponentThe component to render for each file message part.
Unstable_Audio?: Unstable_AudioMessagePartComponentThe component to render for each audio message part.
Reasoning?: ReasoningMessagePartComponentThe component to render for each reasoning message part. Cannot be used alongside ChainOfThought.
tools?: objectConfiguration for tool call rendering. Cannot be used alongside ChainOfThought.
by_name?: Record<string, ToolCallMessagePartComponent>Map of tool names to their specific components.
Fallback?: ToolCallMessagePartComponentFallback component for tool calls not matched by by_name.
Override?: ComponentType<ToolCallMessagePartProps>Override component that handles all tool calls. When set, by_name and Fallback are ignored.
data?: objectConfiguration for data part rendering.
by_name?: Record<string, DataMessagePartComponent>Map of data event names to their specific components.
Fallback?: DataMessagePartComponentFallback component for data events not matched by by_name.
ToolGroup?: ComponentType<PropsWithChildren<{ startIndex: number; endIndex: number }>>Deprecated: This feature is still experimental and subject to change. Component for rendering grouped consecutive tool calls. When provided, consecutive tool-call message parts will be automatically grouped and wrapped with this component. Cannot be used alongside ChainOfThought.
ToolGroupPropsstartIndex: numberIndex of the first tool call in the group.
endIndex: numberIndex of the last tool call in the group.
children: ReactNodeThe rendered tool call components within the group.
ReasoningGroup?: ReasoningGroupComponentComponent for rendering grouped consecutive reasoning parts. Cannot be used alongside ChainOfThought.
ReasoningGroupPropsstartIndex: numberIndex of the first reasoning part in the group.
endIndex: numberIndex of the last reasoning part in the group.
children: ReactNodeThe rendered reasoning part components within the group.
ChainOfThought?: ComponentTypeWhen set, groups all consecutive reasoning and tool-call parts into a single collapsible component. Mutually exclusive with Reasoning, tools, ToolGroup, and ReasoningGroup.
Empty?: EmptyMessagePartComponentComponent to render when the message has no parts, or when unstable_showEmptyOnNonTextEnd is enabled and the last part is not text or reasoning.
unstable_showEmptyOnNonTextEndunstable?: booleanWhen enabled, shows the Empty component if the last part in the message is anything other than Text or Reasoning. Defaults to true.
Quote
Renders a quote block if the message has quote metadata (message.metadata.custom.quote). Place this above MessagePrimitive.Parts.
<MessagePrimitive.Quote>
{({ text, messageId }) => <QuoteBlock text={text} messageId={messageId} />}
</MessagePrimitive.Quote>MessagePrimitiveQuotePropschildren: (quote: QuoteInfo) => ReactNodeRender function called when a quote is present. Receives { text, messageId }.
PartByIndex
Renders a single message part at the specified index.
<MessagePrimitive.PartByIndex
index={0}
components={{
Text: MyTextComponent,
Image: MyImageComponent
}}
/>MessagePrimitive.PartByIndex.Propsindex: numberThe index of the message part to render.
components?: MessagePartComponentsThe components to render for the message part.
Attachments
Renders all attachments of the message.
MessagePrimitive.Attachments.Propscomponents?: AttachmentComponentsThe components to render for each attachment.
AttachmentComponentsImage?: ComponentTypeThe component to render for image attachments.
Document?: ComponentTypeThe component to render for document attachments.
File?: ComponentTypeThe component to render for file attachments.
Attachment?: ComponentTypeThe fallback component to render for any attachment type.
AttachmentByIndex
Renders a single attachment at the specified index within the message.
<MessagePrimitive.AttachmentByIndex
index={0}
components={{
Image: MyImageAttachment,
Document: MyDocumentAttachment
}}
/>MessagePrimitive.AttachmentByIndex.Propsindex: numberThe index of the attachment to render.
components?: AttachmentComponentsThe components to render for the attachment.
useMessageQuote()
A hook that returns the quote info attached to the current message, if any. Reads from message.metadata.custom.quote.
import { useMessageQuote } from "@assistant-ui/react";
const QuoteBlock = () => {
const quote = useMessageQuote();
if (!quote) return null;
return (
<div className="mb-2 flex items-start gap-1.5 text-sm italic text-muted-foreground">
{quote.text}
</div>
);
};Returns: QuoteInfo | undefined
type QuoteInfo = {
readonly text: string; // the quoted plain text
readonly messageId: string; // the source message ID
};See the Quoting guide for a complete walkthrough.
Unstable_PartsGrouped
Renders the parts of a message grouped by a custom grouping function. Use this component when you need to visually group related message parts together — for example, grouping parts that share a common parent ID, or collecting consecutive tool calls under a single header.
The groupingFunction prop controls how parts are grouped. It receives the full array of message parts and must return an array of group descriptors, each with a groupKey (or undefined for ungrouped parts) and an array of indices into the message parts array. The optional components.Group component is then rendered once per group and receives the groupKey, indices, and the rendered part children.
This API is unstable and may change in a future release.
<MessagePrimitive.Unstable_PartsGrouped
groupingFunction={(parts) => {
const groups = new Map<string, number[]>();
parts.forEach((part, i) => {
const key = part.parentId ?? `__ungrouped_${i}`;
const indices = groups.get(key) ?? [];
indices.push(i);
groups.set(key, indices);
});
return Array.from(groups.entries()).map(([key, indices]) => ({
groupKey: key.startsWith("__ungrouped_") ? undefined : key,
indices,
}));
}}
components={{
Text: ({ text }) => <p>{text}</p>,
Group: ({ groupKey, indices, children }) => {
if (!groupKey) return <>{children}</>;
return (
<div className="parent-group">
<h4>Parent: {groupKey}</h4>
{children}
</div>
);
},
}}
/>MessagePrimitive.Unstable_PartsGrouped.PropsgroupingFunction: GroupingFunctionA function that receives the array of message parts and returns an array of groups. Each group has a groupKey (string or undefined for ungrouped parts) and an indices array of part positions.
components?: objectThe components to render for each message part type and for group wrappers.
Text?: TextMessagePartComponentThe component to render for each text message part.
Reasoning?: ReasoningMessagePartComponentThe component to render for each reasoning message part.
Source?: SourceMessagePartComponentThe component to render for each source message part.
Image?: ImageMessagePartComponentThe component to render for each image message part.
File?: FileMessagePartComponentThe component to render for each file message part.
Unstable_Audio?: Unstable_AudioMessagePartComponentThe component to render for each audio message part.
Empty?: EmptyMessagePartComponentComponent to render when the message has no parts.
tools?: objectConfiguration for tool call rendering.
by_name?: Record<string, ToolCallMessagePartComponent>Map of tool names to their specific components.
Fallback?: ToolCallMessagePartComponentFallback component for tool calls not matched by by_name.
Override?: ComponentType<ToolCallMessagePartProps>Override component that handles all tool calls. When set, by_name and Fallback are ignored.
data?: objectConfiguration for data part rendering.
by_name?: Record<string, DataMessagePartComponent>Map of data event names to their specific components.
Fallback?: DataMessagePartComponentFallback component for data events not matched by by_name.
Group?: ComponentType<PropsWithChildren<{ groupKey: string | undefined; indices: number[] }>>Component for rendering a group of message parts. Receives the groupKey (undefined for ungrouped parts), the indices of all parts in the group, and the rendered part children.
GroupPropsgroupKey: string | undefinedThe group key, or undefined for ungrouped parts.
indices: number[]Array of indices of the message parts belonging to this group.
children: ReactNodeThe rendered message part components within the group.
Unstable_PartsGroupedByParentId
A convenience wrapper around MessagePrimitive.Unstable_PartsGrouped that groups message parts by their parentId field. Parts without a parentId appear individually at their chronological position; parts sharing the same parentId are collected into a single group at the position of their first occurrence.
This API is unstable and may change in a future release.
<MessagePrimitive.Unstable_PartsGroupedByParentId
components={{
Group: ({ groupKey, children }) => {
if (!groupKey) return <>{children}</>;
return (
<div className="parent-group border rounded p-4">
<h4>Parent ID: {groupKey}</h4>
{children}
</div>
);
},
}}
/>Accepts the same components prop as MessagePrimitive.Unstable_PartsGrouped, but without a groupingFunction prop (the parent-ID grouping function is applied automatically).
Error
Renders children only if the message has an error status.
<MessagePrimitive.Error>
{/* rendered if the message has an error status */}
<ErrorPrimitive.Root>
<ErrorPrimitive.Message />
</ErrorPrimitive.Root>
</MessagePrimitive.Error>