Skip to content
GitHub

Message

Displays a message in a conversation, with optional avatar, header, footer, and alignment.

HE
Deploying to prod real quick.
PR
It's 4:55 PM. On a Friday.
HE
It's a one-line change.
Delivered
PR
It's always a one-line change 😭.
Alright, let me take a look.
👍
Zelda is typing...
import {
Bubble,
BubbleContent,
BubbleGroup,
BubbleReactions,
} from "@/components/features/pxl/conversation/bubble";
import { Marker, MarkerContent } from "@/components/features/pxl/conversation/marker";
import {
Message,
MessageAvatar,
MessageContent,
MessageFooter,
} from "@/components/features/pxl/conversation/message";
import {
Avatar,
AvatarFallback,
AvatarImage,
} from "@/components/ui/pxl/avatar";
import { Emoji } from "@/components/ui/pxl/emoji";
export default function MessageDemo() {
return (
<div className="flex w-full max-w-sm flex-col gap-6">
<Message align="end">
<MessageAvatar>
<Avatar>
<AvatarImage
className="bg-primary"
src="https://raw.githubusercontent.com/pxl-ui/registry/main/app/public/portraits/hero.png"
alt="@hero"
/>
<AvatarFallback>HE</AvatarFallback>
</Avatar>
</MessageAvatar>
<MessageContent>
<Bubble>
<BubbleContent>Deploying to prod real quick.</BubbleContent>
</Bubble>
</MessageContent>
</Message>
<Message>
<MessageAvatar>
<Avatar>
<AvatarImage
className="bg-success -scale-x-100"
src="https://raw.githubusercontent.com/pxl-ui/registry/main/app/public/portraits/princess.png"
alt="@princess"
/>
<AvatarFallback>PR</AvatarFallback>
</Avatar>
</MessageAvatar>
<MessageContent>
<Bubble variant="muted">
<BubbleContent>It&apos;s 4:55 PM. On a Friday.</BubbleContent>
</Bubble>
</MessageContent>
</Message>
<Message align="end">
<MessageAvatar>
<Avatar>
<AvatarImage
className="bg-primary"
src="https://raw.githubusercontent.com/pxl-ui/registry/main/app/public/portraits/hero.png"
alt="@hero"
/>
<AvatarFallback>HE</AvatarFallback>
</Avatar>
</MessageAvatar>
<MessageContent>
<Bubble>
<BubbleContent>It&apos;s a one-line change.</BubbleContent>
</Bubble>
<MessageFooter>Delivered</MessageFooter>
</MessageContent>
</Message>
<Message>
<MessageAvatar>
<Avatar>
<AvatarImage
className="bg-success -scale-x-100"
src="https://raw.githubusercontent.com/pxl-ui/registry/main/app/public/portraits/princess.png"
alt="@princess"
/>
<AvatarFallback>PR</AvatarFallback>
</Avatar>
</MessageAvatar>
<MessageContent>
<BubbleGroup>
<Bubble variant="muted">
<BubbleContent>
<Emoji>It&apos;s always a one-line change 😭.</Emoji>
</BubbleContent>
</Bubble>
<Bubble variant="muted">
<BubbleContent>Alright, let me take a look.</BubbleContent>
<BubbleReactions aria-label="Reactions: thumbs up">
<Emoji as="span">👍</Emoji>
</BubbleReactions>
</Bubble>
</BubbleGroup>
</MessageContent>
</Message>
<Marker role="status">
<MarkerContent className="shimmer">
<span className="font-medium">Zelda</span> is typing...
</MarkerContent>
</Marker>
</div>
);
}

The Message component lays out a single message in a conversation. It handles the avatar, alignment, header, and footer around the message surface.

For AI apps, you can render reasoning steps, tool calls and assistant messages using the Message component.

pnpm dlx shadcn@latest add pxl-ui/registry/conversation/message
import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/pxl/avatar"
import { Bubble, BubbleContent } from "@/components/features/pxl/conversation/bubble"
import { Message, MessageAvatar, MessageContent } from "@/components/features/pxl/conversation/message"
<Message>
<MessageAvatar>
<Avatar>
<AvatarImage src="https://github.com/shadcn.png" alt="@shadcn" />
<AvatarFallback>CN</AvatarFallback>
</Avatar>
</MessageAvatar>
<MessageContent>
<Bubble>
<BubbleContent>How can I help you today?</BubbleContent>
</Bubble>
</MessageContent>
</Message>

Note: Message owns the row layout—avatar, alignment, header, and footer. Render the visible message surface inside it with Bubble. For the scroll container around a conversation, use MessageScroller.

Use the following composition to build a message:

Message
├── MessageAvatar
└── MessageContent
├── MessageHeader
├── Bubble
└── MessageFooter

Use MessageGroup to stack consecutive messages from the same sender:

MessageGroup
├── Message
└── Message
  • Start and end alignment for sender and receiver rows via the align prop
  • Avatar slot that anchors to the bottom of the message and stays clear of the footer
  • Header and footer slots for sender names, status, and message actions
  • Footer follows the message side; actions stay aligned on align="end" rows
  • Group wrapper for stacking consecutive messages from the same sender
  • Customizable styling through the className prop on every part

Use MessageAvatar to render an avatar next to the message. Set align="end" on the message to align the avatar to the end of the message.

align Description
start Align the message to the start of the conversation.
end Align the message to the end of the conversation.

Use MessageGroup to stack consecutive messages from the same sender. Render an empty MessageAvatar on the earlier messages to keep them aligned with the avatar on the last one.

Use MessageHeader for a sender name and MessageFooter for metadata such as a delivery or read status.

Place message-level actions in MessageFooter, such as copy, retry, or feedback buttons.

Message is a presentational layout wrapper. Accessibility comes from the content you place inside it.

Action buttons in MessageFooter are usually icon-only, so give each one an aria-label.

<MessageFooter>
<Button variant="ghost" size="icon" aria-label="Copy">
<CopyIcon />
</Button>
</MessageFooter>

For in-progress messages, use a Marker with role="status" so assistive tech announces the update as it appears.

<Message>
<Marker role="status">
<MarkerIcon>
<Spinner />
</MarkerIcon>
<MarkerContent>Checking the logs...</MarkerContent>
</Marker>
</Message>

The message row wrapper.

Prop Type Default Description
align "start" | "end" "start" The alignment of the message in the conversation.
className string - Additional classes to apply to the row.

Groups consecutive messages from the same sender.

Prop Type Default Description
className string - Additional classes to apply to the group root.

The avatar slot, aligned to the bottom of the message. When the message has a MessageFooter, the avatar shifts up to stay aligned with the message surface instead of the footer.

Prop Type Default Description
className string - Additional classes to apply to the avatar slot.

Wraps the header, message surface, and footer.

Prop Type Default Description
className string - Additional classes to apply to the content slot.

Displays content above the message, such as a sender name. Stays aligned to the start regardless of align.

Prop Type Default Description
className string - Additional classes to apply to the header.

Displays content below the message, such as status or actions. Aligns to the message side.

Prop Type Default Description
className string - Additional classes to apply to the footer.