Message

A single chat message from the person or the assistant, in three layouts.

Loading preview…

Install

  1. 1

    Run this command in your Tailwind CSS project. It adds components/ai/message-bubbles.tsx and installs its dependencies.

    $ npx shadcn@latest add https://gradientdeck.com/ai-components/r/message-bubbles.json

Usage & API

Example

message-bubbles.tsx
import { MessageBubble } from "@/components/ai/message-bubbles"

<MessageBubble
  role="user"
  children={children}
/>

Props MessageBubble

PropType & descriptionRequired
role"user" | "assistant"Required
childrenReactNodeRequired
metastringShown under the bubble, e.g. a time or "Edited".Optional

Dependencies

  • React
  • Tailwind CSS
  • motion
Implementation notes

Bubbles exports MessageBubble. role is user or assistant. The entrance is a short rise and fade. The user bubble uses the sand tone and dark text. The assistant bubble uses a white or zinc surface, a border, and a light shadow. There is no name prop and no avatar image. The orb is decorative and aria-hidden. meta is optional and unstyled beyond size and color, so pass a short string. The typing indicator in the demo is a sibling: a status labelled Assistant is typing, the same orb, and three dots delayed by 0.15 seconds. The demo script shows a user turn, an assistant turn, then a second user turn, the typing row, then the second assistant turn. Copy the sequence if you want that pause. Do not look for a typing prop on MessageBubble.

Choosing a layout

Use Bubbles for a two-party chat where the person's turns and the assistant's turns should be obvious at a glance. Meta is the right place for 9:41 or for Edited after Edit message saves. Use Document when the assistant answer is something to read, with steps and code, and the person's prompt should look like a quoted brief rather than a pill. The demo asks about a slow Postgres query and answers with an ordered list and code for EXPLAIN ANALYZE and VACUUM ANALYZE. Use Compact when several people and an assistant share one log. The demo channel is labelled # launch-checklist. The assistant name gets an AI badge. A user avatar is the first character of the name on the color you pass.

Streaming text belongs inside the children, or in place of them, while tokens are still arriving. Message does not take a shown count or a caret. Message actions sits under an assistant turn. It is not built into these layouts. Branch picker is how you step between alternate versions of one reply. The compact continued flag is your job. Compare the previous author id, and pass continued so the second bubble does not show a second avatar. The demo does that for the assistant's follow-up question about opening a pull request.

Can I pass a markdown string as children and get headings?

No. children is a React node, rendered as is. Document will style h4, ol, code and strong if you pass those elements, which is what the Postgres demo does. A raw string stays a paragraph. For a string that is still streaming, use Streaming text, whose markdown variant parses headings, lists and fences while the source is incomplete. When the stream finishes, you can keep that view or replace it with Message.

How does a second assistant paragraph avoid a second avatar in the compact log?

Pass continued. The component then skips the avatar, the name and the AI badge, and only shows the time in the gutter while the row is hovered. It does not compare authors. If you forget the flag, every call renders a full header, even when the name matches the previous row. The time string is also what the hover gutter slices. 10:02 AM shows 10:02 there, because it splits on the space.