AI
MessageAI
The layout of one turn in a conversation: who wrote it, where it aligns, and slots for header, content and footer.
npx prodular-ui add messageUser and assistant
User text in a bubble on the right. Assistant text on the page, under a header with the AI mark.
import { AiMark } from "@/components/ui/ai-mark"import { Bubble, BubbleContent } from "@/components/ui/bubble"import { Message, MessageContent, MessageHeader, MessageMeta } from "@/components/ui/message"import { Response } from "@/components/ui/response"
export default function MessageThread() { return ( <div className="flex w-full max-w-xl flex-col gap-8"> <Message from="user"> <MessageContent> <Bubble align="end"> <BubbleContent>How much do we owe Northbeam this month?</BubbleContent> </Bubble> </MessageContent> </Message> <Message from="assistant"> <MessageContent className="gap-2"> <MessageHeader> <AiMark model="Generated by Claude Sonnet 5" /> Ledgerline Copilot <MessageMeta>9:42</MessageMeta> </MessageHeader> <Response> {"You owe Northbeam Logistics **$27,852.50** across two open invoices. INV-20931 ($18,240.50) is due on October 30, and INV-20977 ($9,612.00) on November 14."} </Response> </MessageContent> </Message> </div> )}With avatars
For shared threads where several people talk to the assistant.
import { AiMark } from "@/components/ui/ai-mark"import { Bubble, BubbleContent } from "@/components/ui/bubble"import { Message, MessageAvatar, MessageContent, MessageFooter, MessageHeader, MessageMeta,} from "@/components/ui/message"
export default function MessageAvatars() { return ( <div className="flex w-full max-w-xl flex-col gap-6"> <Message from="user"> <MessageAvatar>PS</MessageAvatar> <MessageContent className="gap-1"> <MessageHeader> Priya Shah <MessageMeta>10:14</MessageMeta> </MessageHeader> <Bubble align="end"> <BubbleContent>Can you flag any invoice over $10,000 without a PO?</BubbleContent> </Bubble> </MessageContent> </Message> <Message from="assistant"> <MessageAvatar> <AiMark /> </MessageAvatar> <MessageContent className="gap-1"> <MessageHeader> Ledgerline Copilot <MessageMeta>10:14</MessageMeta> </MessageHeader> <p> Three invoices match. I added the flag Needs PO to each and assigned them to Daniel Ortiz in Procurement. </p> <MessageFooter>Edited 2 fields in Payables</MessageFooter> </MessageContent> </Message> </div> )}Anatomy
<Message from="assistant"> <MessageContent> <MessageHeader><AiMark /> Copilot</MessageHeader> <Response>{text}</Response> </MessageContent></Message>Guidance
Use it when
- For every turn in a chat, an agent run log or a comment thread with an assistant in it.
- from="user" aligns to the end, from="assistant" to the start.
Avoid
- Putting assistant answers in a Bubble. Long answers read better on the page.
- Avatars in one to one chats. A header with the AI mark is enough.
Rules for AI agents
Published in llms-full.txt and the registry, so coding agents follow them when they build with this component.
- Always set from on Message. Assistant messages carry data-from="assistant", which is how generated content is marked in a thread.
- Inside an assistant message, render parts in the order they were produced: MessageHeader, Reasoning, tool calls, Response, Sources, MessageActions, follow-up Suggestions.
- Put the AI mark in MessageHeader or MessageAvatar of assistant messages, with model set to the model that produced it.
- Wrap each Message in MessageScrollerItem when the thread scrolls.
API
Message
| Prop | Type | Default | Description |
|---|---|---|---|
| from | "user" | "assistant" | "system" | Author. Sets data-from and the default alignment. | |
| align | "start" | "end" | end for user, start otherwise | Override the side. |
MessageMeta
| Prop | Type | Default | Description |
|---|---|---|---|
| children | ReactNode | Time, model or status next to the name, 12px. |