rapidUI

Message

Chat message layout with avatar, author, content and actions.

Installation

pnpm dlx shadcn@latest add https://rdf.dev.360online.com/r/message.json

Installs to @/components/ui/message.

Manual installation

Copy the source into your project:

components/ui/message.tsx
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.

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