GitHub
Core
Glass
Brutal
Humanist

Chat Message
Pro

Complete messaging component system for building modern chat interfaces. Supports multiple message types (text, icon, image, file), sender-based layouts, inline reply previews, fully customizable emoji reactions, and smooth spring-animated reaction triggers.

Chat Message Playground

Chat Message Playground
Preview
Code
Adam Smith
Adam Smith

Can you provide me with more details on the project?

06:04 AM

Controls
Sender:
Other
User
Type:
Text
Icon
Image
File
Avatar:
Name:
Reply:
Reaction:

Installation

You can add the chat message component to your project manually:

1

Install the following dependencies:

npm install class-variance-authority clsx tailwind-merge @phosphor-icons/react @react-aria/interactions
2

Copy and paste the following code into your project.

Loading...
3

Update the import paths to match your project setup.

Update the import aliases (e.g. @/components, @/utils) in the copied files to match your project's path configuration.

Basic Usage

import { ChatMessage } from '@versaui/ui/components/ChatMessage';

// Basic text message from another user
<ChatMessage
    sender="other"
    senderName="Alice"
    message="Hey, how's the project going?"
    timestamp="10:30 AM"
/>

// User's own message
<ChatMessage
    sender="user"
    message="It's going great, thanks!"
    timestamp="10:31 AM"
/>

Variants

Sender

Messages align and style differently based on sender:

// Other user — left aligned, secondary color, with avatar
<ChatMessage sender="other" senderName="Bob" />

// Current user — right aligned, neutral color, no avatar
<ChatMessage sender="user" />

Message Types

Four content types are supported:

// Text only
<ChatMessage messageType="text" message="Hello!" />

// Icon message (e.g. missed call)
<ChatMessage messageType="icon" iconLabel="Missed call" />

// Image message
<ChatMessage messageType="image" imageUrl="/photo.jpg" message="Check this out" />

// File attachment
<ChatMessage messageType="file" fileName="report.pdf" fileSize="412 KB" />

State

Hover state adds elevation shadow and reveals the react button:

<ChatMessage state="default" />
<ChatMessage state="hovered" />

With Reply

Show an inline reply preview inside the bubble:

<ChatMessage
    reply
    replyProps={{ type: 'text', senderName: 'Alice', content: 'Original message' }}
    message="Yes, I agree!"
/>

With Reactions

Show emoji reaction pills below the bubble with dynamic emoji items:

<ChatMessage
    reaction
    reactionProps={{
        reactions: [
            { emoji: '❤️', count: 3 },
            { emoji: '🎉', count: 1 },
            { emoji: '🔥' },
        ]
    }}
    message="Great idea!"
/>

Sub-Components

ChatReply

Inline reply preview shown inside the chat bubble:

import { ChatReply } from '@versaui/ui/components/ChatMessage';

<ChatReply type="text" senderName="Alice" content="Original message" />
<ChatReply type="icon" content="Missed call" />
<ChatReply type="image" imageUrl="/photo.jpg" />
<ChatReply type="file" fileName="report.pdf" fileSize="412 KB" />

Reactions

Emoji reaction cluster pill beneath a message. Supports any custom emoji array, adaptive padding, fixed 20×20px frame centering with baseline typography, and scale pop transitions:

import { Reactions } from '@versaui/ui/components/ChatMessage';

// Dynamic reaction data
<Reactions
    reactions={[
        { emoji: '❤️', count: 4 },
        { emoji: '👍🏻', count: 2 },
        { emoji: '🚀' },
    ]}
    onReactionClick={(reaction, index) => console.log('Clicked:', reaction)}
    onAddClick={() => console.log('Add reaction')}
/>

// Single emoji (count omitted automatically)
<Reactions reactions={[{ emoji: '❤️' }]} />

ReactButton

Smiley icon trigger that opens an elevated Material popover with quick-pick emojis and spring animations:

import { ReactButton } from '@versaui/ui/components/ChatMessage';

<ReactButton
    onReact={(emoji) => console.log('Reacted with:', emoji)}
    onMoreClick={() => console.log('More clicked')}
/>

Accessibility

  • Messages use semantic HTML with appropriate ARIA labels
  • Reactions use aria-label describing the emoji content
  • React button uses aria-expanded and click-outside listeners to manage popover visibility
  • Material popover menu uses role="menu" with role="menuitem" for emoji options
  • More options button has descriptive aria-label
  • Reply preview uses role="blockquote" with attribution

Chat Message Props

PropTypeDefaultDescription
sender'user' | 'other''other'Message sender determining alignment, colors, and layout.
messageType'text' | 'icon' | 'image' | 'file''text'Content type of the message.
state'default' | 'hovered''default'Controlled visual state. Auto-detected via hover when unset.
avatarbooleantrueShow avatar (other sender only).
namebooleantrueShow sender name (other sender only).
senderNamestring'Adam Smith'Display name of the sender.
messagestring'Can you provide me with more details on the project?'Message text content.
timestampstring'06:04 AM'Timestamp string displayed beside the message.
replybooleanfalseShow inline reply preview.
replyPropsChatReplyProps—Props passed to the ChatReply sub-component.
reactionbooleanfalseShow reaction pills below the bubble.
reactionPropsReactionsProps—Props passed to the Reactions sub-component.
imageUrlstring—Image URL for image-type messages.
changeIconReactNode—Custom icon for icon-type messages.
iconLabelstring'Missed call'Label text for icon-type messages.
fileNamestring'Sample file.pdf'File name for file-type messages.
fileSizestring'412 KB'File size for file-type messages.
avatarPersonAvatarPerson'adam-smith'Predefined avatar person key from the design system.
onMoreClick() => void—More options button click handler.
onReact(emoji: string) => void—Emoji reaction selection handler.
classNamestring''Additional CSS classes.

Chat Reply Props

PropTypeDefaultDescription
type'text' | 'icon' | 'image' | 'file''text'Content type of the replied-to message.
senderNamestring'Adam Smith'Original sender display name.
contentstring'Can you provide me with more details...'Original text or description.
imageUrlstring—Image URL for image-type replies.
fileNamestring'Sample file.pdf'File name for file-type replies.
fileSizestring'412 KB'File size for file-type replies.
iconReactNode—Custom icon for icon-type replies.
classNamestring''Additional CSS classes.

Reactions Props

PropTypeDefaultDescription
reactionsReactionData[]—Custom array of reaction items ({ emoji, count, id, ariaLabel }).
variant'1' | '2' | '2+''2+'Preset reaction variant when custom reactions are not provided.
interactivebooleantrueWhether reaction emojis and the add button are clickable.
onReactionClick(reaction: ReactionData, index: number) => void—Called when a reaction emoji is clicked.
onAddClick() => void—Called when the add (+) reaction button is clicked.
renderEmoji(emoji: string, item: ReactionData) => ReactNode—Custom renderer for individual emoji elements.
classNamestring''Additional CSS classes.

React Button Props

PropTypeDefaultDescription
state'default' | 'hovered' | 'selected''default'Controlled visual state.
isOpenboolean—Controlled open state for the reaction options overlay.
onOpenChange(open: boolean) => void—Callback fired when overlay opens or closes.
quickEmojisstring[]['❤️', '🙂', '👍🏻', '🎉', '😔']List of quick-pick emojis shown in the popover overlay.
onReact(emoji: string) => void—Called when an emoji is selected from the overlay.
onMoreClick() => void—Called when the more (+) button in the overlay is clicked.
classNamestring''Additional CSS classes.

On this page