Installation
pnpm dlx shadcn@latest add https://rdf.dev.360online.com/r/message.jsonInstalls to @/components/ui/message.
Manual installation
Copy the source into your project:
import type * as React from 'react'
import { cn } from '@/lib/utils'
function MessageGroup({ className, ...props }: React.ComponentProps<'div'>) {
return <div data-slot="message-group" className={cn('flex min-w-0 flex-col gap-2', className)} {...props} />
}
function Message({ className, align = 'start', ...props }: React.ComponentProps<'div'> & { align?: 'start' | 'end' }) {
return (
<div
data-slot="message"
data-align={align}
className={cn(
'group/message relative flex w-full min-w-0 gap-2 text-sm data-[align=end]:flex-row-reverse',
className,
)}
{...props}
/>
)
}
function MessageAvatar({ className, ...props }: React.ComponentProps<'div'>) {
return (
<div
data-slot="message-avatar"
className={cn(
'flex w-fit min-w-8 shrink-0 items-center justify-center self-end group-has-data-[slot=message-footer]/message:-translate-y-8',
className,
)}
{...props}
/>
)
}
function MessageContent({ className, ...props }: React.ComponentProps<'div'>) {
return (
<div
data-slot="message-content"
className={cn(
'flex w-full min-w-0 flex-col gap-2.5 wrap-break-word group-data-[align=end]/message:*:data-slot:self-end',
className,
)}
{...props}
/>
)
}
function MessageHeader({ className, ...props }: React.ComponentProps<'div'>) {
return (
<div
data-slot="message-header"
className={cn(
'flex max-w-full min-w-0 items-center px-3 text-xs font-medium text-muted-foreground group-has-data-[variant=ghost]/message:px-0',
className,
)}
{...props}
/>
)
}
function MessageFooter({ className, ...props }: React.ComponentProps<'div'>) {
return (
<div
data-slot="message-footer"
className={cn(
'flex max-w-full min-w-0 items-center px-3 text-xs font-medium text-muted-foreground group-has-data-[variant=ghost]/message:px-0 group-data-[align=end]/message:justify-end',
className,
)}
{...props}
/>
)
}
export { MessageGroup, Message, MessageAvatar, MessageContent, MessageFooter, MessageHeader }Displays a message in a conversation, with an optional avatar, header, footer and start or end alignment. Message is the layout wrapper for chat transcripts and composes with Bubble, Attachment and Marker.
Features
- Start and end alignment
- Avatar anchored to the bottom of the message
- Header and footer slots for author, time and actions
- MessageGroup for consecutive messages
- Composes with Bubble, Attachment and Marker
Usage
import { Avatar, AvatarFallback } from '@/components/ui/avatar'
import { Bubble, BubbleContent } from '@/components/ui/bubble'
import { Message, MessageAvatar, MessageContent, MessageHeader } from '@/components/ui/message'
export function OfficerMessage() {
return (
<Message>
<MessageAvatar>
<Avatar>
<AvatarFallback>AL</AvatarFallback>
</Avatar>
</MessageAvatar>
<MessageContent>
<MessageHeader>Anna Lindqvist</MessageHeader>
<Bubble variant="muted">
<BubbleContent>Your application has been registered.</BubbleContent>
</Bubble>
</MessageContent>
</Message>
)
}Examples
Default
A message with avatar, header and bubble.
Alignment
Messages from both sides.
With Header And Footer
Author with role badge, time and a read receipt.
Grouped
Several bubbles from the same sender.
With Attachment
A message with a file attachment.
Assistant
An assistant-style answer with footer actions and a hand-over marker.
Not Sent
A failed message with a destructive bubble and a retry action in the footer.
Accessibility
- Wrap transcripts in a container with an accessible name (e.g. role="log")
- Avatars are decorative when the author is named in the header
- Give icon-only footer actions an aria-label
- Convey status icons such as read receipts with text alternatives