Ballmac UI home

AI Message

A chat message with user, assistant and system roles: right-aligned user bubbles, full-width assistant prose, an avatar slot, hover-revealed actions and a hydration-safe timestamp.

YO
How do I keep a chat scrolled to the newest message while it streams?
AI

Stick to the bottom only while the reader is already there. Track whether the scroll position is within a few pixels of the end; if it is, scroll down as new tokens arrive. If they scrolled up, leave them and show a “jump to latest” button instead.

Installation

$ pnpm dlx shadcn@latest add @ballmac/ai-message

Usage

import { Message, MessageAvatar, MessageContent, MessageActions, MessageAction, MessageCopyAction, MessageTimestamp } from "@/components/ballmac/ai-message"

The full example is in the Code tab above.

Examples

With actions

AI

Use useTransition to keep the input responsive while the list re-renders; wrap only the expensive state update in startTransition.

API reference

<Message>

PropTypeDefault
role

Who sent the message. User messages sit right in a bubble; assistant messages run full width; system messages are centered notes.

MessageRole"assistant"

<MessageActions>

PropTypeDefault
visibility

"hover" reveals the row on hover or keyboard focus on devices with a mouse (always visible on touch). "always" keeps it visible.

"hover" | "always""hover"

<MessageAction>

PropTypeDefault
label*

Accessible name for the icon-only button, also shown as a native tooltip.

string—

<MessageCopyAction>

PropTypeDefault
value*

Text written to the clipboard, usually the message's raw markdown.

string—
label

Accessible name before copying.

string—
onCopied

Called after the text was copied.

() => void—

<MessageTimestamp>

PropTypeDefault
date*

When the message was sent.

Date | string | number—
locale

BCP 47 locale for formatting.

string—
timeZone

IANA time zone. When omitted the viewer's zone is used, formatted after hydration so server and browser agree.

string—
format

Intl.DateTimeFormat options.

Intl.DateTimeFormatOptions{ hour: "numeric", minute: "2-digit" }
children

Preformatted text; overrides the built-in formatting.

React.ReactNode—

Also accepts the standard attributes of its root element.

Accessibility

KeyAction
TabMoves through the action buttons; focusing any of them reveals the action row
Enter / SpaceRuns the focused action

Use with AI

Render one chat turn. <Message role> wraps <MessageAvatar>, <MessageContent>, <MessageActions> (with <MessageAction label> and <MessageCopyAction value>) and <MessageTimestamp date>. It takes plain children, so it works with the Vercel AI SDK, LangChain or any stream. With the shadcn MCP server set up (guide), ask your agent:

Add the Ballmac UI AI Message (@ballmac/ai-message) to this project with the shadcn MCP, then use it where it fits.

Use it for

  • Rendering each turn of an assistant or chatbot conversation
  • Showing copy, regenerate and feedback buttons under an assistant reply
  • A system note inside a conversation, such as 'Model switched to a smaller context window'

Not for

  • The scrolling conversation layout itself (use ai-chat and put messages inside ChatMessages)
  • Threaded comments or email-style lists where both sides look alike

Registry JSON: https://ui.ballmac.com/r/ai-message.json

Credits

Free to use in personal and commercial projects.