Message

Preview

YouNow
What should we include in the first release?
Sent
AssistantNow
Start with the smallest workflow that still feels complete.

Install

Add it with the shadcn CLI, or copy the source manually.

$ bunx --bun shadcn add @beui/message

API Reference

Message

from
"user" | "assistant"
Default—
animateIn?
boolean

Plays a trailing-edge pop-up once when this message row mounts.

Defaultfalse
className?
string
Default—

MessageGroup

spacing?
"compact" | "default"
Defaultcompact
className?
string
Default—

MessageAvatar

placeholder?
boolean

Keep an empty avatar slot so grouped messages remain aligned.

Defaultfalse
className?
string
Default—

MessageContent

className?
string
Default—

MessageHeader

className?
string
Default—

MessageFooter

className?
string
Default—

MessageMarker

className?
string
Default—

MessageTyping

label?
string
DefaultResponding
className?
string
Default—

MessageBubble

variant?
"solid" | "soft" | "tint" | "outline" | "ghost" | "danger"
Defaultsoft
align?
"start" | "end"

Defaults to the surrounding Message alignment when omitted.

Default—
animateIn?
boolean

Plays the bubble entrance once when this component mounts.

Defaultfalse
className?
string
Default—

MessageBubbleCollapsible

open?
boolean
Default—
defaultOpen?
boolean
Defaultfalse
onOpenChange?
((open: boolean) => void)
Default—
collapsedLines?
2 | 3 | 4 | 5 | 6
Default4
moreLabel?
ReactNode
DefaultShow more
lessLabel?
ReactNode
DefaultShow less
contentClassName?
string
Default—
triggerClassName?
string
Default—
className?
string
Default—

MessageBubbleContent

render?
ReactElement<unknown, string | JSXElementConstructor<any>>

Replaces the content element while preserving bubble styling.

Default—
className?
string
Default—

MessageBubbleGroup

spacing?
"compact" | "default"
Defaultcompact
className?
string
Default—

MessageScroller

followOutput?
boolean

Keep streamed output pinned while the reader remains near the end.

Defaulttrue
followThreshold?
number

Distance from the end that still counts as following the output.

Default56
smooth?
boolean

Smoothly follow growing content.

Defaulttrue
onFollowChange?
((following: boolean) => void)

Reports when the reader leaves or returns to the live edge.

Default—
label?
string

Accessible label for the scrollable transcript.

DefaultConversation
busy?
boolean

Marks the transcript as waiting for more streamed content.

Default—
navigation?
"rail"

Adds a compact rail for navigating between rendered Message rows.

Default—
navigationLabel?
string

Accessible label for the optional message navigation rail.

DefaultMessage navigation
viewportClassName?
string
Default—
contentClassName?
string
Default—
railClassName?
string
Default—
viewportRef?
Ref<HTMLElement>
Default—
viewportProps?
Omit<DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>, "children" | "ref" | "className">
Default—
contentProps?
Omit<DetailedHTMLProps<HTMLAttributes<HTMLDivElement>, HTMLDivElement>, "children" | "ref" | "className">
Default—
className?
string
Default—

Composition

Build each conversation row from independent identity, content, and metadata primitives.

MessageGroup
└── Message
    ├── MessageAvatar
    └── MessageContent
        ├── MessageHeader
        ├── MessageBubble
        └── MessageFooter

Note: Message Bubble supplies the visual surface inside the row. Message Scroller positions message rows inside a reader-aware transcript. Agent Activity renders progressive agent work as message content.

How it works

A message is a conversation row. It coordinates the avatar, metadata, content surface, and delivery details while allowing the content itself to be a bubble, an agent activity, a tool result, or a composed response.

Also on React Native. Rows that rise out of their corner, with avatars and typing dots.

Updated